/*
  File:    GhostFluidMethod.cpp
  Purpose: Advanced method for solving discontinuous Poisson problem
           on irregular domains. Second-order accuracy with brand-new
           discretization of [grad(u).n] = 0. Solves the following problem

           0 = div( DiffusionConstant grad(u) ) + SourceFunction 
		                                       + SourceFunctionU * u
           [u] = JumpCondition(x,y)
           [grad(u).n] = 0

  Contact: Paul Macklin
           pmacklin@math.uci.edu
		  http://math.uci.edu/~pmacklin
*/

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath>

using namespace std;

#include "../Matrix.h"
#include "../ImprovedMath.h"
// #include "../band.h"
#include "../random.h"
#include "../ParseText.h"
#include "../Edinburgh_Angio/myangio.h"
//#include "DiffusionSolverSteadyState.h "
/*
extern double dx;
extern double dy;
extern double _EPS;
*/

Matrix Iteration_Change_Matrix;

double JunkZeroFunction(double x, double y )
{ return 0.0; }

double gfmImplicitUpdateNew( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   Matrix& DiffusionConstant, Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy );
   
double gfmImplicitUpdateNew( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   double(*InteriorDiffusivity)(double,double),
   double(*ExteriorDiffusivity)(double,double),
   Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy );

/* these are the new ones on 3-5-2007 */
   
double gfmImplicitUpdateDiscontinuousD( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   double(*InteriorDiffusivity)(double,double),
   double(*ExteriorDiffusivity)(double,double),
   Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy );   
   
double gfmImplicitUpdateDiscontinuousD( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   Matrix& InteriorDiffusivity,
   Matrix& ExteriorDiffusivity,
   Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy );   
   

#include "GeometricData.h"
#include "Curvature.h"

class SolverPoint{
public:
	int i;
	int j;
	SolverPoint* pNextSolverPoint;
	SolverPoint();
};

SolverPoint::SolverPoint()
{ i=0; j=0; pNextSolverPoint = NULL; }

bool CompareRegions( double input1, double input2 )
{
 extern double _EPS;
 
 if( input1 > _EPS && input2 > _EPS )
 { return true; }
 if( input1 <= _EPS && input2 <= _EPS )
 { return true; }
 return false;
}

double gfmImplicitUpdate( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   Matrix& DiffusionConstant, Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double), int i, int j, double dx, double dy )
{
 extern double _EPS;


 double Uij = *Solution(i,j);
 double dt = 1.0;
 double dx2 = square(dx);
 double dy2 = square(dy);


 double Dx_ell = 0.5*( *DiffusionConstant(i-1,j) + *DiffusionConstant(i,j) );
 double Dx_r   = 0.5*( *DiffusionConstant(i+1,j) + *DiffusionConstant(i,j) );
 double Dy_ell = 0.5*( *DiffusionConstant(i,j-1) + *DiffusionConstant(i,j) );
 double Dy_r   = 0.5*( *DiffusionConstant(i,j+1) + *DiffusionConstant(i,j) );
 
 double OutputCoefficientLHS = 1.0/dt; 
 double OutputCoefficientRHS = 0.0;
 double Output = Uij/dt;

 bool DoneX = false;
 bool DoneXleft  = false;
 bool DoneXright = false;
 
 bool DoneY = false;
 bool DoneYleft  = false;
 bool DoneYright = false; 
 
 // do the x-derivative
 // right side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
 {
  Output += *Solution(i+1,j) *Dx_r/dx2; 
  OutputCoefficientRHS -= Dx_r/dx2;
  DoneXright = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i+1,j)) );
  double GhostCoefficient = Dx_r/dx2;
  double UinnerCoefficient = 0.0;
  // get ghost point u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i-2,j) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i-2,j)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i-1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneXright = true;
  }				  
  // linear
  if( !DoneXright  )
  { 
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i-1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXright = true;
   }
  }				  
  // constant
  if( !DoneXright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)+Theta*dx , *Y(j) );
  if( *Phi(i,j) > _EPS )
  { *JumpConditionRHS(0) *= -1.0; }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXright = false;
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)+Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
      CompareRegions( *Phi(i+1,j),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 2.0-Theta;
   double UyOuter = 0.0;
   double VxOuter = 1.0-Theta;
   double VyOuter = 1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = -(1.0+Theta);
   double UyInner = 0.0;
   double VxInner = -Theta;
   double VyInner = -1.0;
   
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
   
   *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
   *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
   *JumpConditionRHS(1) = *Solution(i-1,j)*AlphaInner 
                        + *Solution(i,j-1)*BetaInner
                        - *Solution(i+2,j)*AlphaOuter
						- *Solution(i+1,j+1)*BetaOuter;
   DoneXright = true; 
  }  

  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+1,j),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i-1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 2.0-Theta;
    double UyOuter = 0.0;
    double VxOuter = 1.0-Theta;
    double VyOuter = -1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = -(1.0+Theta);
    double UyInner = 0.0;
    double VxInner = -Theta;
    double VyInner = 1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
    *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
    *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
    *JumpConditionRHS(1) = *Solution(i-1,j)*AlphaInner 
                         + *Solution(i,j+1)*BetaInner
                         - *Solution(i+2,j)*AlphaOuter
	                     - *Solution(i+1,j-1)*BetaOuter;
    DoneXright = true; 
   }   
  }

  if( !DoneXright )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = 1.0/(2.0-Theta);
    *JumpConditionRHS(1) = *Solution(i+2,j)/(2.0-Theta) + *Solution(i-1,j)/(1.0+Theta);
    DoneXright = true; 
   }
  }   
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = *Solution(i-1,j);
    DoneXright = true; 
   } 
  }
  if( !DoneXright )
  {  
   if( CompareRegions( *Phi(i+2,j) , *Phi(i+1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = *Solution(i+2,j);
    DoneXright = true; 
   }
  }  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXright )
  { Uinner = *Solution(i+1,j) + *JumpConditionRHS(0); }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // left side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
 {
  Output += *Solution(i-1,j) *Dx_ell/dx2; 
  OutputCoefficientRHS -= Dx_ell/dx2;
  DoneXleft = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i-1,j)) );
  double GhostCoefficient = Dx_ell/dy2;
  double UinnerCoefficient = 0.0;
  
  // get ghost point u_{i-1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i+2,j) )  )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i+2,j) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i+1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));   
   DoneXleft = true;
  }
  // linear
  if( !DoneXleft  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i+1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXleft = true;
   }
  }				  
  // constant
  if( !DoneXleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)-Theta*dx , *Y(j) );
  if( *Phi(i,j) > _EPS )
  { *JumpConditionRHS(0) *= -1.0; }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)-Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
      CompareRegions( *Phi(i-1,j),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = -(2.0-Theta);
   double UyOuter = 0.0;
   double VxOuter = -(1.0-Theta);
   double VyOuter = -1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);
   
   double UxInner = (1.0+Theta);
   double UyInner = 0.0;
   double VxInner = Theta;
   double VyInner = 1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
   *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
   *JumpConditionRHS(1) = *Solution(i+1,j)*AlphaInner 
                        + *Solution(i,j+1)*BetaInner
                        - *Solution(i-2,j)*AlphaOuter
						- *Solution(i-1,j-1)*BetaOuter;
   DoneXleft = true; 
  }  

  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-1,j),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i+1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = -(2.0-Theta);
    double UyOuter = 0.0;
    double VxOuter = -(1.0-Theta);
    double VyOuter = 1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = (1.0+Theta);
    double UyInner = 0.0;
    double VxInner = Theta;
    double VyInner = -1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
    *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
    *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
    *JumpConditionRHS(1) = *Solution(i+1,j)*AlphaInner 
                         + *Solution(i,j-1)*BetaInner
                         - *Solution(i-2,j)*AlphaOuter
	                     - *Solution(i-1,j+1)*BetaOuter;
    DoneXleft = true; 
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = 1.0/(2.0-Theta);
    *JumpConditionRHS(1) = *Solution(i-2,j)/(2.0-Theta) + *Solution(i+1,j)/(1.0+Theta);
    DoneXleft = true; 
   }
  }  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) ) // typo!!
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = *Solution(i+1,j);
    DoneXleft = true; 
   }
  }  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-2,j) , *Phi(i-1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = *Solution(i-2,j);
    DoneXleft = true; 
   }
  }  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXleft )
  { Uinner = *Solution(i-1,j) + *JumpConditionRHS(0); }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // do the y-derivative
 // right side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) )  )
 {
  Output += *Solution(i,j+1) *Dy_r/dy2; 
  OutputCoefficientRHS -= Dy_r/dy2;
  DoneYright = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j+1)) );
  double GhostCoefficient = Dy_r/dy2;
  double UinnerCoefficient = 0.0;
  // get ghost phone u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i,j-2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j-2)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j-1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneYright = true;
  }				  
  // linear
  if( !DoneYright  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j-1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYright = true;
   }
  }				  
  // constant
  if( !DoneYright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)+Theta*dy );
  if( *Phi(i,j) > _EPS )
  { *JumpConditionRHS(0) *= -1.0; }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)+Theta*dy);
  
  if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
      CompareRegions( *Phi(i,j+1),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = 2.0-Theta;
   double VxOuter = 1.0;
   double VyOuter = 1.0-Theta;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = -(1.0+Theta);
   double VxInner = -1.0;
   double VyInner = -Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
   
   *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
   *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
   *JumpConditionRHS(1) = *Solution(i,j-1)*AlphaInner 
                        + *Solution(i-1,j)*BetaInner
                        - *Solution(i,j+2)*AlphaOuter
						- *Solution(i+1,j+1)*BetaOuter;
   DoneYright = true; 
  }  

  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+1),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j-1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = 2.0-Theta;
    double VxOuter = -1.0;
    double VyOuter = 1.0-Theta;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = -(1.0+Theta);
    double VxInner = 1.0;
    double VyInner = -Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
    *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
    *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
    *JumpConditionRHS(1) = *Solution(i,j-1)*AlphaInner 
                         + *Solution(i+1,j)*BetaInner
                         - *Solution(i,j+2)*AlphaOuter
	                     - *Solution(i-1,j+1)*BetaOuter;
    DoneYright = true; 
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = 1.0/(2.0-Theta);
    *JumpConditionRHS(1) = *Solution(i,j+2)/(2.0-Theta) + *Solution(i,j-1)/(1.0+Theta);
    DoneYright = true; 
   }  
  }
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = *Solution(i,j-1);
    DoneYright = true; 
   }
  }  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = *Solution(i,j+2);
    DoneYright = true; 
   }
  }  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYright )
  { Uinner = *Solution(i,j+1) + *JumpConditionRHS(0); }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // left side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
 {
  Output += *Solution(i,j-1) *Dy_ell/dy2; 
  OutputCoefficientRHS -= Dy_ell/dy2;
  DoneYleft = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j-1)) );
  double GhostCoefficient = Dy_ell/dy2;
  double UinnerCoefficient = 0.0;

  // get ghost phone u_{i-1}
  // quadratic
  if( !DoneYleft && CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) 
                 && CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j+2) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j+1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));     
   DoneYleft = true;
  }				  
  // linear
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j+1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYleft = true;
   }
  }				  
  // constant
  if( !DoneYleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)-Theta*dy );
  if( *Phi(i,j) > _EPS )
  { *JumpConditionRHS(0) *= -1.0; }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)-Theta*dy);
  
  if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
      CompareRegions( *Phi(i,j-1),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS   )
  {
   double UxOuter = 0.0;
   double UyOuter = -(2.0-Theta);
   double VxOuter = -1.0;
   double VyOuter = -(1.0-Theta);
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = 1.0+Theta;
   double VxInner = 1.0;
   double VyInner = Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
   
   *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
   *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
   *JumpConditionRHS(1) = *Solution(i,j+1)*AlphaInner 
                        + *Solution(i+1,j)*BetaInner
                        - *Solution(i,j-2)*AlphaOuter
						- *Solution(i-1,j-1)*BetaOuter;
   DoneYleft = true; 
  }  

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-1),*Phi(i+1,j-1) ) && // typo this line: (i+1,j+1)
 	   CompareRegions( *Phi(i,j),*Phi(i,j+1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS   )
   {
    double UxOuter = 0.0;
    double UyOuter = -(2.0-Theta);
    double VxOuter = 1.0;
    double VyOuter = -(1.0-Theta);
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = 1.0+Theta;
    double VxInner = -1.0;
    double VyInner = Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
    *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
    *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
    *JumpConditionRHS(1) = *Solution(i,j+1)*AlphaInner 
                         + *Solution(i-1,j)*BetaInner
                         - *Solution(i,j-2)*AlphaOuter
	                     - *Solution(i+1,j-1)*BetaOuter;
    DoneYleft = true; 
   }   
  }  

  if( !DoneYleft )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = 1.0/(2.0-Theta);
    *JumpConditionRHS(1) = *Solution(i,j-2)/(2.0-Theta) + *Solution(i,j+1)/(1.0+Theta);
    DoneYleft = true; 
   }  
  } 
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) ) // typo!!
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = *Solution(i,j+1);
    DoneYleft = true; 
   }  
  }
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = *Solution(i,j-2);
    DoneYleft = true; 
   }
  }  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYleft )
  { Uinner = *Solution(i,j-1) + *JumpConditionRHS(0); }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 if( DoneXright && DoneXleft )
 { DoneX = true; }
 if( DoneYright && DoneYleft )
 { DoneY = true; }
 
 // add a non-diffusion case here
 if( !DoneX && !DoneY ) 
 {  
  Output += ( *Solution(i-1,j) * Dx_ell + *Solution(i+1,j) *Dx_r )/dx2;
  Output += ( *Solution(i,j-1) * Dy_ell + *Solution(i,j+1) *Dy_r )/dy2;
  OutputCoefficientRHS -= ( (Dx_ell+Dx_r)/dx2 + (Dy_ell+Dy_r)/dy2 );         
 }
 
 // sourcde 
 OutputCoefficientRHS += *SourceFunctionU(i,j);
 Output += *SourceFunction(i,j);
 Output /= (OutputCoefficientLHS-OutputCoefficientRHS);
 
 return Output; 
}   


double gfmUpdateBoundaryPoint( Matrix& X, Matrix& Y, Matrix& Solution,
                            double (*LeftBC)(double),   char LeftBCtype,  
                            double (*RightBC)(double),  char RightBCtype,     
                            double (*BottomBC)(double), char BottomBCtype,   
                            double (*TopBC)(double),    char TopBCtype,  
                            int i, int j )
{
 double x = *X(i);
 double y = *Y(j);
 if( i == 0 )
 {  
  if( LeftBCtype == 'd' || LeftBCtype == 'D' )
  { return LeftBC(y); }
  if( LeftBCtype == 'n' || LeftBCtype == 'N' )
  { return (4* *Solution(1,j) - *Solution(2,j) - 2*LeftBC(y) )/3.0; }  
  if( LeftBCtype == 'e' || LeftBCtype == 'E' )
  {
   return 3.0*(*Solution(1,j)-*Solution(2,j)) + *Solution(3,j);
   return 4.0* *Solution(i+1,j) 
         -6.0* *Solution(i+2,j)
         +4.0* *Solution(i+3,j)
         -1.0* *Solution(i+4,j);
  }
  return 1.0;   
 }
 
 if( i == Solution.TellRows() - 1)
 {
  if( RightBCtype == 'd' || RightBCtype == 'D' )
  { return RightBC(y); }
  if( RightBCtype == 'n' || RightBCtype == 'N' )
  { return (2*RightBC(y) + 4* *Solution(i-1,j) - *Solution(i-2,j) )/3.0; }  
  if( RightBCtype == 'e' || RightBCtype == 'E' )
  { 
   return 3.0*(*Solution(i-1,j)-*Solution(i-2,j)) + *Solution(i-3,j); 
   return 4.0* *Solution(i-1,j) 
         -6.0* *Solution(i-2,j)
         +4.0* *Solution(i-3,j)
         -1.0* *Solution(i-4,j);
  }
  return 2.0;   
 }

 if( j == 0 )
 {  
  if( BottomBCtype == 'd' || BottomBCtype == 'D' )
  { return BottomBC(x); }
  if( BottomBCtype == 'n' || BottomBCtype == 'N' )
  { return (4* *Solution(i,1) - *Solution(i,2) - 2*BottomBC(x) )/3.0; }  
  if( BottomBCtype == 'e' || BottomBCtype == 'E' )
  {
   return 3.0*(*Solution(i,1)-*Solution(i,2)) + *Solution(i,3); 
   return 4.0* *Solution(i,j+1) 
         -6.0* *Solution(i,j+2)
         +4.0* *Solution(i,j+3)
         -1.0* *Solution(i,j+4);
  }
  return 3.0;   
 }
 
 if( j == Solution.TellCols() - 1)
 {
  if( TopBCtype == 'd' || TopBCtype == 'D' )
  { return TopBC(x); }
  if( TopBCtype == 'n' || TopBCtype == 'N' )
  { return (2*TopBC(x) + 4* *Solution(i,j-1) - *Solution(i,j-2) )/3.0; }  
  if( TopBCtype == 'e' || TopBCtype == 'E' )
  {
   return 3.0*(*Solution(i,j-1)-*Solution(i,j-2)) + *Solution(i,j-3);
   return 4.0* *Solution(i,j-1) 
         -6.0* *Solution(i,j-2)
         +4.0* *Solution(i,j-3)
         -1.0* *Solution(i,j-4);
  }
  return 4.0;   
 }
 return 5;
}							

Matrix GhostFluidMethodNonAdaptive_Deprecated( Matrix &X, Matrix &Y, Matrix &Phi, 
   Matrix& DiffusionConstant, Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance ) 
{
 extern double dx;
 extern double dy;
 


 int i,j;

 Matrix Output = InitialGuess; 
 
 int Iteration = 0;
 double Error = 2*Tolerance;
 
 bool GiveUp = false;
 int GiveUpThreshold = (int) floor( (0.015*X.TellCols())*(0.015*Y.TellCols()) );
 int Count = 0;
 
 while( Iteration < MaxIterations && Error > Tolerance )
 {
  if( Iteration % 1000 == 0 && Iteration > 0 )
  { cout << Iteration << " " << Error << endl; } 
 
  Error = 0; 
  Count = 0;
  
  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   j=Y.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   i=X.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }					
 
  if( Iteration % 4 == 0 )
  {  
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j=1 ; j < Y.TellCols()-1 ; j++ )
    {
     double PNewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 double change = fabs( PNewValue - *Output(i,j) );

	 if( change > Error )
	 { Error = change; }
     
     if( change > 0.75*Tolerance )
     { Count++; }     
     
	 *Output(i,j) = PNewValue;
	 
    }
   }
   
  }
  if( Iteration % 4 == 1 )
  {
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
     
     if( change > 0.75*Tolerance )
     { Count++; }     
     
	 *Output(i,j) = NewValue;
	 
    }
   }
   
  }
  if( Iteration % 4 == 2 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
     
     if( change > 0.75*Tolerance )
     { Count++; }     
     
	 *Output(i,j) = NewValue;
	 
    }
   }
   
  }

  if( Iteration % 4 == 3 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = 1 ; j < Y.TellCols()-1 ; j++ )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
     
     if( change > 0.75*Tolerance )
     { Count++; }     
     
	 *Output(i,j) = NewValue;
	 
    }
   }
   if( Count < GiveUpThreshold )
   { GiveUp = true; }
  }

  Iteration++;
 } 
 cout << "summary:: iterations: " << Iteration << endl
      << "          error     : " << Error << endl << endl;
 if( GiveUp )
 {
  cout << "Gave up because effort was being focused on less than 0.0225% of nodes!" << endl 
       << "(" << Count << " nodes)" << endl << endl; 
 }
	   
 return Output;
}

Matrix GhostFluidMethod_Deprecated( Matrix &X, Matrix &Y, Matrix &Phi, 
   Matrix& DiffusionConstant, Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance )
{
 extern double dx;
 extern double dy;

 int i,j;

 Matrix Output = InitialGuess; 
 
 int Iteration = 0;
 double Error = 2*Tolerance;

 double SelectionRatio = 0.25;
 double SelectionCriterion = Tolerance; 

 int MaxSolverPoints = 10*X.TellCols(); 
 int NumberOfSolverPoints = 0;
 
 int* Inodes;
 int* Jnodes;
 
 Inodes = new int [MaxSolverPoints];
 Jnodes = new int [MaxSolverPoints];
 
 int k=0;
 while( Iteration < MaxIterations && Error > Tolerance )
 {
  Error = 0; 

  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   j=Y.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   i=X.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }					
 
  if( k % 4 == 0 )
  {  
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j=1 ; j < Y.TellCols()-1 ; j++ )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 double change = fabs( NewValue - *Output(i,j) );
	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  Inodes[NumberOfSolverPoints] = i;
	  Jnodes[NumberOfSolverPoints] = j;
	  NumberOfSolverPoints++;
	 }
	 
    }
   }

   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    int m;
    for( m = 0 ; m < NumberOfSolverPoints ; m++ )
	{
	 i = Inodes[m];
	 j = Jnodes[m];
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	}
    for( m = 0 ; m < NumberOfSolverPoints ; m++ )
	{
	 i = Inodes[m];
	 j = Jnodes[m];
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	}
    NumberOfSolverPoints=0;
   }
   
  }
  if( k % 4 == 1 )
  {
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;

	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  Inodes[NumberOfSolverPoints] = i;
	  Jnodes[NumberOfSolverPoints] = j;
	  NumberOfSolverPoints++;
	 }
	 
	 
    }
   }
   
   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    int m;
    for( m = 0 ; m < NumberOfSolverPoints ; m++ )
	{
	 i = Inodes[m];
	 j = Jnodes[m];
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	}
    for( m = 0 ; m < NumberOfSolverPoints ; m++ )
	{
	 i = Inodes[m];
	 j = Jnodes[m];
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	}
    NumberOfSolverPoints=0;   
   }
   
  }
  if( k % 4 == 2 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  Inodes[NumberOfSolverPoints] = i;
	  Jnodes[NumberOfSolverPoints] = j;
	  NumberOfSolverPoints++;
	 }
	 
    }
   }
   
   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    int m;
    for( m = 0 ; m < NumberOfSolverPoints ; m++ )
	{
	 i = Inodes[m];
	 j = Jnodes[m];
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	}
    for( m = 0 ; m < NumberOfSolverPoints ; m++ )
	{
	 i = Inodes[m];
	 j = Jnodes[m];
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	}
    NumberOfSolverPoints=0;   
   }
   
  }
  if( k % 4 == 3 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = 1 ; j < Y.TellCols()-1 ; j++ )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  Inodes[NumberOfSolverPoints] = i;
	  Jnodes[NumberOfSolverPoints] = j;
	  NumberOfSolverPoints++;	 
	 }
	 
	 
    }
   }

   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    int m;
    for( m = 0 ; m < NumberOfSolverPoints ; m++ )
	{
	 i = Inodes[m];
	 j = Jnodes[m];
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	}
    for( m = 0 ; m < NumberOfSolverPoints ; m++ )
	{
	 i = Inodes[m];
	 j = Jnodes[m];
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	}
    NumberOfSolverPoints=0;   
   }
  }

  k++;
  Iteration++;
 }
 cout << "summary:: iterations: " << Iteration << endl
      << "          error     : " << Error << endl << endl;
 return Output;
}

Matrix GhostFluidMethodOld_Deprecated( Matrix &X, Matrix &Y, Matrix &Phi, 
   Matrix& DiffusionConstant, Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance )
{
 extern double dx;
 extern double dy;

 int i,j;

 Matrix Output = InitialGuess; 
 
 int Iteration = 0;
 double Error = 2*Tolerance;

 double SelectionRatio = 0.25;
 double SelectionCriterion = Tolerance; 

 SolverPoint* pHeadSolverPoint = NULL;
 SolverPoint* pCurrentSolverPoint = pHeadSolverPoint;

 int MaxSolverPoints = 10*X.TellCols(); 
 int NumberOfSolverPoints = 0;
 
 bool GiveUp = false;
 int GiveUpThreshold = (int) floor( (0.015*X.TellCols())*(0.015*Y.TellCols()) );
// int GiveUpThreshold = 20;
 
 int k=0;
 while( Iteration < MaxIterations && Error > Tolerance && !GiveUp )
 {
  if( Iteration % 1000 == 0 && Iteration > 0 )
  { cout << Iteration << " " << Error << endl; }
  Error = 0; 

  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   j=Y.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   i=X.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }					

  
  if( k % 4 == 0 )
  {  
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j=1 ; j < Y.TellCols()-1 ; j++ )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 double change = fabs( NewValue - *Output(i,j) );
	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
    }
   }

   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 1 )
  {
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;

	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
	 
    }
   }
   
   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
	// temp on 2-1-2007
	GiveUp = false;
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 2 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
    }
   }
   
   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 3 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = 1 ; j < Y.TellCols()-1 ; j++ )
    {
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
	 
    }
   }

   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint;
  
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
     
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
   }
   NumberOfSolverPoints = 0;
  }

  k++;
  Iteration++;
 }
 cout << "summary:: iterations: " << Iteration << endl
      << "          error     : " << Error << endl << endl;
 if( GiveUp )
 {
  cout << "Gave up because adaptivity was being focused on less than 0.0225% of nodes!" << endl
       << "(" << NumberOfSolverPoints << " nodes)" << endl << endl; 
 } 
 return Output;
}

Matrix GhostFluidMethodRandom_Deprecated( Matrix &X, Matrix &Y, Matrix &Phi, 
   Matrix& DiffusionConstant, Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance )
{
 extern double dx;
 extern double dy;

 int i,j;

 Matrix Output = InitialGuess; 
 
 int Iteration = 0;
 double Error = 2*Tolerance;

 double SelectionRatio = 0.25;
 double SelectionCriterion = Tolerance; 

 SolverPoint* pHeadSolverPoint = NULL;
 SolverPoint* pCurrentSolverPoint = pHeadSolverPoint;

 int MaxSolverPoints = 10*X.TellCols(); 
 int NumberOfSolverPoints = 0;
 
 int IterationGrouping = X.TellCols()*Y.TellCols();
 
 int k=0;
 while( Iteration < MaxIterations && Error > Tolerance )
 {
  if( Iteration % 1000 == 0 && Iteration > 0 )
  { cout << Iteration << " " << Error << endl; }
  Error = 0;

  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   j=Y.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   i=X.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }					
  
  for( int k=0 ; k < IterationGrouping ; k++ )
  {
   int i = 1 + ImprovedRound(  UniformRandom() * (X.TellCols()-3) );
   int j = 1 + ImprovedRound(  UniformRandom() * (Y.TellCols()-3) );
  
   double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
   double change = fabs( NewValue - *Output(i,j) );
   if( change > Error )
   { Error = change; }
   *Output(i,j) = NewValue;
  }   
  
  Iteration++;
 }
 cout << "summary:: iterations: " << Iteration << endl
      << "          error     : " << Error << endl << endl;
 return Output;
}


Matrix GhostFluidMethodNew_Deprecated( Matrix &X, Matrix &Y, Matrix &Phi, 
   Matrix& DiffusionConstant, Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double),
   Matrix& InitialGuess, int MaxIterations, double Tolerance )
{
 extern double dx;
 extern double dy;

 int i,j;

 Matrix Output = InitialGuess; 
 
 int Iteration = 0;
 double Error = 2*Tolerance;

 double SelectionRatio = 0.25;
 double SelectionCriterion = Tolerance; 

 SolverPoint* pHeadSolverPoint = NULL;
 SolverPoint* pCurrentSolverPoint = pHeadSolverPoint;

 int MaxSolverPoints = 10*X.TellCols(); 
 int NumberOfSolverPoints = 0;
 
 bool GiveUp = false;
 int GiveUpThreshold = (int) floor( (0.015*X.TellCols())*(0.015*Y.TellCols()) );
// int GiveUpThreshold = 20;
 
 int k=0;
 while( Iteration < MaxIterations && Error > Tolerance && !GiveUp )
 {
  if( Iteration % 1000 == 0 && Iteration > 0 )
  { cout << Iteration << " " << Error << endl; }
  Error = 0; 

  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   j=Y.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   i=X.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }					

  
  if( k % 4 == 0 )
  {  
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j=1 ; j < Y.TellCols()-1 ; j++ )
    {
/*	
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	 
	 double NewValue = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	 double change = fabs( NewValue - *Output(i,j) );
	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
    }
   }

   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 1 )
  {
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
/*	
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 double NewValue = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);

 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;

	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
	 
    }
   }
   
   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 *Output(i,j) = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
	// temp on 2-1-2007
	GiveUp = false;
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 2 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
/*
	 double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	 

	 double NewValue = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);

 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
    }
   }
   
   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);

     pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 3 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = 1 ; j < Y.TellCols()-1 ; j++ )
    {
/*	
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 double NewValue = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
	 
    }
   }

   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 *Output(i,j) = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 *Output(i,j) = gfmImplicitUpdateNew(X,Y,Phi,Output, 
	 DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint;
  
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
	GiveUp = false; // 2-1-2007
     
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
   }
   NumberOfSolverPoints = 0;
  }

  k++;
  Iteration++;
 }
 cout << "summary:: iterations: " << Iteration << endl
      << "          error     : " << Error << endl << endl;
 if( GiveUp )
 {
  cout << "Gave up because adaptivity was being focused on less than 0.0225% of nodes!" << endl
       << "(" << NumberOfSolverPoints << " nodes)" << endl << endl; 
 } 
 return Output;
}

double gfmImplicitUpdateNew( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   Matrix& DiffusionConstant, Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy )
{
/*
 return gfmImplicitUpdate(X,Y,Phi,Solution, 
   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,
   i,j,dx,dy);
*/
 extern double _EPS;

// NormalDerivativeJumpCondition = JunkZeroFunction;

 double Uij = *Solution(i,j);
 double dt = 1.0;
 double dx2 = square(dx);
 double dy2 = square(dy);


 double Dx_ell = 0.5*( *DiffusionConstant(i-1,j) + *DiffusionConstant(i,j) );
 double Dx_r   = 0.5*( *DiffusionConstant(i+1,j) + *DiffusionConstant(i,j) );
 double Dy_ell = 0.5*( *DiffusionConstant(i,j-1) + *DiffusionConstant(i,j) );
 double Dy_r   = 0.5*( *DiffusionConstant(i,j+1) + *DiffusionConstant(i,j) );
 
 double OutputCoefficientLHS = 1.0/dt; 
 double OutputCoefficientRHS = 0.0;
 double Output = Uij/dt;

 bool DoneX = false;
 bool DoneXleft  = false;
 bool DoneXright = false;
 
 bool DoneY = false;
 bool DoneYleft  = false;
 bool DoneYright = false; 
 
 // do the x-derivative
 // right side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
 {
  Output += *Solution(i+1,j) *Dx_r/dx2; 
  OutputCoefficientRHS -= Dx_r/dx2;
  DoneXright = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i+1,j)) );
  double GhostCoefficient = Dx_r/dx2;
  double UinnerCoefficient = 0.0;
  // get ghost point u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i-2,j) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i-2,j)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i-1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneXright = true;
  }				  
  // linear
  if( !DoneXright  )
  { 
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i-1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXright = true;
   }
  }				  
  // constant
  if( !DoneXright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)+Theta*dx , *Y(j) );
  
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)+Theta*dx , *Y(j) ); 
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0; 
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXright = false;
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)+Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
      CompareRegions( *Phi(i+1,j),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS && 1 == 1 )
  {
   double UxOuter = 2.0-Theta;
   double UyOuter = 0.0;
   double VxOuter = 1.0-Theta;
   double VyOuter = 1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = -(1.0+Theta);
   double UyInner = 0.0;
   double VxInner = -Theta;
   double VyInner = -1.0;
   
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
   
   *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
   *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
   *JumpConditionRHS(1) = -NormalDerivativeJump*dx + *Solution(i-1,j)*AlphaInner 
                        + *Solution(i,j-1)*BetaInner
                        - *Solution(i+2,j)*AlphaOuter
						- *Solution(i+1,j+1)*BetaOuter;
   DoneXright = true; 
  }  

  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+1,j),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i-1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS && 1 == 1 )
   {
    double UxOuter = 2.0-Theta;
    double UyOuter = 0.0;
    double VxOuter = 1.0-Theta;
    double VyOuter = -1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = -(1.0+Theta);
    double UyInner = 0.0;
    double VxInner = -Theta;
    double VyInner = 1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
    *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
    *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
    *JumpConditionRHS(1) = -NormalDerivativeJump*dx + *Solution(i-1,j)*AlphaInner 
                         + *Solution(i,j+1)*BetaInner
                         - *Solution(i+2,j)*AlphaOuter
	                     - *Solution(i+1,j-1)*BetaOuter;
    DoneXright = true; 
   }   
  }
  
  if( !DoneXright )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) && fabs(GDP.NormalX) > 0 )
   {
    int s = 1;
	if( GDP.NormalX < 0 )
	{ s = -1; }
   
//    cout << GDP.NormalX << endl;
    *JumpConditionCoefficientMatrix(1,0) = 1.0/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = 1.0/(2.0-Theta);
    *JumpConditionRHS(1) = dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                       *Solution(i+2,j)/(2.0-Theta) + *Solution(i-1,j)/(1.0+Theta);
    DoneXright = true; 
   }
  }   
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 1 == 1 )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = (1.0+Theta)*(*Solution(i,j)) - Theta*(*Solution(i-1,j)); 
	                     // *Solution(i-1,j); // 2-1-2007
    DoneXright = true; 
   } 
  }
  if( !DoneXright )
  {  
   if( CompareRegions( *Phi(i+2,j) , *Phi(i+1,j) ) && 1 == 1 )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i+2,j)) - (1.0-Theta)*(*Solution(i+1,j)); 
	                     // *Solution(i+2,j); // 2-1-2007
    DoneXright = true; 
   }
  }  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXright && 1 == 1 )
  { Uinner = *Solution(i+1,j) + *JumpConditionRHS(0); }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 // left side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
 {
  Output += *Solution(i-1,j) *Dx_ell/dx2; 
  OutputCoefficientRHS -= Dx_ell/dx2;
  DoneXleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i-1,j)) );
  double GhostCoefficient = Dx_ell/dy2;
  double UinnerCoefficient = 0.0;
  
  // get ghost point u_{i-1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i+2,j) )  )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i+2,j) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i+1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));   
   DoneXleft = true;
  }
  // linear
  if( !DoneXleft  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i+1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXleft = true;
   }
  }				  
  // constant
  if( !DoneXleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)-Theta*dx , *Y(j) );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)-Theta*dx,*Y(j) );
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)-Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
      CompareRegions( *Phi(i-1,j),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS && 1 == 1 )
  {
   double UxOuter = -(2.0-Theta);
   double UyOuter = 0.0;
   double VxOuter = -(1.0-Theta);
   double VyOuter = -1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);
   
   double UxInner = (1.0+Theta);
   double UyInner = 0.0;
   double VxInner = Theta;
   double VyInner = 1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
   *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
   *JumpConditionRHS(1) = -NormalDerivativeJump*dx + *Solution(i+1,j)*AlphaInner 
                        + *Solution(i,j+1)*BetaInner
                        - *Solution(i-2,j)*AlphaOuter
						- *Solution(i-1,j-1)*BetaOuter;
   DoneXleft = true; 
  }  

  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-1,j),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i+1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS && 1 == 1 )
   {
    double UxOuter = -(2.0-Theta);
    double UyOuter = 0.0;
    double VxOuter = -(1.0-Theta);
    double VyOuter = 1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = (1.0+Theta);
    double UyInner = 0.0;
    double VxInner = Theta;
    double VyInner = -1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
    *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
    *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
    *JumpConditionRHS(1) = -NormalDerivativeJump*dx + *Solution(i+1,j)*AlphaInner 
                         + *Solution(i,j-1)*BetaInner
                         - *Solution(i-2,j)*AlphaOuter
	                     - *Solution(i-1,j+1)*BetaOuter;
    DoneXleft = true; 
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) && fabs(GDP.NormalX) > 0 )
   {
    int s = 1;
	if( GDP.NormalX < 0 )
	{ s = -1; }
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = 1.0/(2.0-Theta);
    *JumpConditionRHS(1) = -dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                     *Solution(i-2,j)/(2.0-Theta) + *Solution(i+1,j)/(1.0+Theta);
    DoneXleft = true; 
   }
  }  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 1 == 1 )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = (1.0+Theta)*(*Solution(i,j)) - Theta*( *Solution(i+1,j));
	                     // *Solution(i+1,j); // 2-1-2007
    DoneXleft = true; 
   }
  }  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-2,j) , *Phi(i-1,j) ) && 1 == 1 )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i-1,j)) - (1.0-Theta)*(*Solution(i-2,j)); 
	                      // *Solution(i-2,j); // 2-1-2007
    DoneXleft = true; 
   }
  }  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXleft && 1 == 1 )
  { Uinner = *Solution(i-1,j) + *JumpConditionRHS(0); }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // do the y-derivative
 // right side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) )  )
 {
  Output += *Solution(i,j+1) *Dy_r/dy2; 
  OutputCoefficientRHS -= Dy_r/dy2;
  DoneYright = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j+1)) );
  double GhostCoefficient = Dy_r/dy2;
  double UinnerCoefficient = 0.0;
  // get ghost phone u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i,j-2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j-2)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j-1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneYright = true;
  }				  
  // linear
  if( !DoneYright  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j-1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYright = true;
   }
  }				  
  // constant
  if( !DoneYright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)+Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i) , *Y(j)+Theta*dy );
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;  
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)+Theta*dy);
  
  if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
      CompareRegions( *Phi(i,j+1),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS && 1 == 1 )
  {
   double UxOuter = 0.0;
   double UyOuter = 2.0-Theta;
   double VxOuter = 1.0;
   double VyOuter = 1.0-Theta;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = -(1.0+Theta);
   double VxInner = -1.0;
   double VyInner = -Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
   
   *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
   *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
   *JumpConditionRHS(1) = -NormalDerivativeJump*dy + *Solution(i,j-1)*AlphaInner 
                        + *Solution(i-1,j)*BetaInner
                        - *Solution(i,j+2)*AlphaOuter
						- *Solution(i+1,j+1)*BetaOuter;
   DoneYright = true; 
  }  

  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+1),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j-1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS && 1 == 1 )
   {
    double UxOuter = 0.0;
    double UyOuter = 2.0-Theta;
    double VxOuter = -1.0;
    double VyOuter = 1.0-Theta;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = -(1.0+Theta);
    double VxInner = 1.0;
    double VyInner = -Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
    *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
    *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
    *JumpConditionRHS(1) = -NormalDerivativeJump*dy + *Solution(i,j-1)*AlphaInner 
                         + *Solution(i+1,j)*BetaInner
                         - *Solution(i,j+2)*AlphaOuter
	                     - *Solution(i-1,j+1)*BetaOuter;
    DoneYright = true; 
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) && fabs(GDP.NormalY) > 0 )
   {
    int s = 1;
	if( GDP.NormalY < 0 )
	{ s = -1; }
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = 1.0/(2.0-Theta);
    *JumpConditionRHS(1) = dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                       *Solution(i,j+2)/(2.0-Theta) + *Solution(i,j-1)/(1.0+Theta);
    DoneYright = true; 
   }  
  }
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = (1.0+Theta)*(*Solution(i,j)) - Theta*(*Solution(i,j-1));
	// *Solution(i,j-1); // 2-1-2007
    DoneYright = true; 
   }
  }  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j+1)) - (1.0-Theta)*(*Solution(i,j+2));
	// *Solution(i,j+2); // 2-1-2007
    DoneYright = true; 
   }
  }  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYright )
  { Uinner = *Solution(i,j+1) + *JumpConditionRHS(0); }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // left side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
 {
  Output += *Solution(i,j-1) *Dy_ell/dy2; 
  OutputCoefficientRHS -= Dy_ell/dy2;
  DoneYleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j-1)) );
  double GhostCoefficient = Dy_ell/dy2;
  double UinnerCoefficient = 0.0;

  // get ghost phone u_{i-1}
  // quadratic
  if( !DoneYleft && CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) 
                 && CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j+2) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j+1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));     
   DoneYleft = true;
  }				  
  // linear
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j+1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYleft = true;
   }
  }				  
  // constant
  if( !DoneYleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)-Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i),*Y(j)-Theta*dy);
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;   
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)-Theta*dy);
  
  if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
      CompareRegions( *Phi(i,j-1),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS && 1 == 1 )
  {
   double UxOuter = 0.0;
   double UyOuter = -(2.0-Theta);
   double VxOuter = -1.0;
   double VyOuter = -(1.0-Theta);
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = 1.0+Theta;
   double VxInner = 1.0;
   double VyInner = Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
   
   *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
   *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
   *JumpConditionRHS(1) = -NormalDerivativeJump*dy + *Solution(i,j+1)*AlphaInner 
                        + *Solution(i+1,j)*BetaInner
                        - *Solution(i,j-2)*AlphaOuter
						- *Solution(i-1,j-1)*BetaOuter;
   DoneYleft = true; 
  }  

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-1),*Phi(i+1,j-1) ) && // typo this line: (i+1,j+1)
 	   CompareRegions( *Phi(i,j),*Phi(i,j+1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS && 1 == 1 )
   {
    double UxOuter = 0.0;
    double UyOuter = -(2.0-Theta);
    double VxOuter = 1.0;
    double VyOuter = -(1.0-Theta);
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = 1.0+Theta;
    double VxInner = -1.0;
    double VyInner = Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
    *JumpConditionCoefficientMatrix(1,0) = AlphaInner+BetaInner; 
    *JumpConditionCoefficientMatrix(1,1) = -(AlphaOuter+BetaOuter);
    *JumpConditionRHS(1) = -NormalDerivativeJump*dy + *Solution(i,j+1)*AlphaInner 
                         + *Solution(i-1,j)*BetaInner
                         - *Solution(i,j-2)*AlphaOuter
	                     - *Solution(i+1,j-1)*BetaOuter;
    DoneYleft = true; 
   }   
  }  

  if( !DoneYleft )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) && fabs(GDP.NormalY) > 0 )
   {
    double s = GDP.NormalY;
	if( fabs( s ) < 1e-10 )
	{
 	 s = 1;
     if( GDP.NormalY <= 0 )
	 { s = -1; }
	}
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = 1.0/(2.0-Theta);
    *JumpConditionRHS(1) = -dy*NormalDerivativeJump/s + // /GDP.NormalY + 
	                     *Solution(i,j-2)/(2.0-Theta) + *Solution(i,j+1)/(1.0+Theta);
    DoneYleft = true; 
   }  
  } 
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = (1.0+Theta)*(*Solution(i,j)) - Theta*(*Solution(i,j+1));
	// *Solution(i,j+1); // 2-1-2007
    DoneYleft = true; 
   }  
  }
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j-1)) - (1.0-Theta)*(*Solution(i,j-2)); 
	// *Solution(i,j-2); // 2-1-2007
    DoneYleft = true; 
   }
  }  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYleft )
  { Uinner = *Solution(i,j-1) + *JumpConditionRHS(0); }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 if( DoneXright && DoneXleft )
 { DoneX = true; }
 if( DoneYright && DoneYleft )
 { DoneY = true; }
 
 // add a non-diffusion case here
 if( !DoneX && !DoneY ) 
 {  
  Output += ( *Solution(i-1,j) * Dx_ell + *Solution(i+1,j) *Dx_r )/dx2;
  Output += ( *Solution(i,j-1) * Dy_ell + *Solution(i,j+1) *Dy_r )/dy2;
  OutputCoefficientRHS -= ( (Dx_ell+Dx_r)/dx2 + (Dy_ell+Dy_r)/dy2 );         
 }
 
 // source 
 OutputCoefficientRHS += *SourceFunctionU(i,j);
 Output += *SourceFunction(i,j);
 Output /= (OutputCoefficientLHS-OutputCoefficientRHS);
 
 return Output; 
}   

Matrix GhostFluidMethodNew_Deprecated( Matrix &X, Matrix &Y, Matrix &Phi, 
   double (*InteriorDiffusivity)(double,double), 
   double (*ExteriorDiffusivity)(double,double),   
   Matrix& SourceFunction, Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance )
{
 extern double dx;
 extern double dy;

 int i,j;

 Matrix Output = InitialGuess; 
 
 int Iteration = 0;
 double Error = 2*Tolerance;

 double SelectionRatio = 0.25;
 double SelectionCriterion = Tolerance; 

 SolverPoint* pHeadSolverPoint = NULL;
 SolverPoint* pCurrentSolverPoint = pHeadSolverPoint;

 int MaxSolverPoints = 10*X.TellCols(); 
 int NumberOfSolverPoints = 0;
 
 bool GiveUp = false;
 int GiveUpThreshold = (int) floor( (0.015*X.TellCols())*(0.015*Y.TellCols()) );
// int GiveUpThreshold = 20;
 
 int k=0;
 while( Iteration < MaxIterations && Error > Tolerance && !GiveUp )
 {
  if( Iteration % 1000 == 0 && Iteration > 0 )
  { cout << Iteration << " " << Error << endl; }
  Error = 0; 

  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   j=Y.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   i=X.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }					

  
  if( k % 4 == 0 )
  {  
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j=1 ; j < Y.TellCols()-1 ; j++ )
    {
/*	
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	 
	 double NewValue = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	 double change = fabs( NewValue - *Output(i,j) );
	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
    }
   }

   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 1 )
  {
   for( i=1 ; i < X.TellCols()-1 ; i++ )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
/*	
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 double NewValue = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);

 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;

	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
	 
    }
   }
   
   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 *Output(i,j) = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
	// temp on 2-1-2007
	GiveUp = false;
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 2 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = Y.TellCols()-2 ; j > 0 ; j-- )
    {
/*
	 double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	 

	 double NewValue = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);

 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
    }
   }
   
   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
     pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/	   
	 *Output(i,j) = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint; 
    
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
    
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
	NumberOfSolverPoints = 0;
   }
   
  }
  if( k % 4 == 3 )
  {
   for( i = X.TellCols()-2 ; i > 0 ; i-- )
   {
    for( j = 1 ; j < Y.TellCols()-1 ; j++ )
    {
/*	
     double NewValue = gfmImplicitUpdate(X,Y,Phi,Output,
     DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 double NewValue = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
 	 double change = fabs( NewValue - *Output(i,j) ); 
 	 if( change > Error )
	 { Error = change; }
	 *Output(i,j) = NewValue;
	 
	 if( Iteration % 4 == 1 && change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	 {
	  SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
	 
    }
   }

   if( Iteration % 4 == 0 )
   { SelectionCriterion = SelectionRatio*Error; }
   else
   {
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 *Output(i,j) = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
    pCurrentSolverPoint = pHeadSolverPoint; 
	while( pCurrentSolverPoint )
	{
	 i = pCurrentSolverPoint->i;
	 j = pCurrentSolverPoint->j;
/*	 
	 *Output(i,j) = gfmImplicitUpdate(X,Y,Phi,Output,
	   DiffusionConstant,SourceFunction,SourceFunctionU,JumpCondition,i,j,dx,dy);
*/
	 *Output(i,j) = gfmImplicitUpdateDiscontinuousD(X,Y,Phi,Output, 
	 InteriorDiffusivity,ExteriorDiffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	   
	 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint; 
	}
	Iteration += 2;
    pCurrentSolverPoint = pHeadSolverPoint;
  
    if( NumberOfSolverPoints < GiveUpThreshold ) 
    { GiveUp = true; }
	GiveUp = false; // 2-1-2007
     
	while( pHeadSolverPoint )
	{
	 pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
	 delete pHeadSolverPoint;
	 pHeadSolverPoint = pCurrentSolverPoint;
	}
   }
   NumberOfSolverPoints = 0;
  }

  k++;
  Iteration++;
 }
 cout << "summary:: iterations: " << Iteration << endl
      << "          error     : " << Error << endl << endl;
 if( GiveUp )
 {
  cout << "Gave up because adaptivity was being focused on less than 0.0225% of nodes!" << endl
       << "(" << NumberOfSolverPoints << " nodes)" << endl << endl; 
 } 
 return Output;
}   
   
double gfmImplicitUpdateNew( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   double(*InteriorDiffusivity)(double,double),
   double(*ExteriorDiffusivity)(double,double),
   Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy )
{
 bool outer_off_grid = true;
 bool inner_off_grid = true;
 bool outer_on_grid  = true;
 bool inner_on_grid  = true;
 
 bool our_new_method = false;
 bool higher_fedkiw = true; 
 
 if( !our_new_method )
 { higher_fedkiw = false; }
 
 bool low_order = true;
 
 if( low_order )
 {
  outer_off_grid = false;
  outer_on_grid = false;
  inner_on_grid = false;
  inner_off_grid = false;
  
  higher_fedkiw = false;
 }
 
 bool quad = true;
 bool lin = true;
 
 bool show_message = false;

 extern double _EPS;

// NormalDerivativeJumpCondition = JunkZeroFunction;

 double Uij = *Solution(i,j);
 double dt = 1;
 double dx2 = square(dx);
 double dy2 = square(dy);

/*
 double Dx_ell = 0.5*( *DiffusionConstant(i-1,j) + *DiffusionConstant(i,j) );
 double Dx_r   = 0.5*( *DiffusionConstant(i+1,j) + *DiffusionConstant(i,j) );
 double Dy_ell = 0.5*( *DiffusionConstant(i,j-1) + *DiffusionConstant(i,j) );
 double Dy_r   = 0.5*( *DiffusionConstant(i,j+1) + *DiffusionConstant(i,j) );
 
 double Dx_ell = 0.5*( *DiffusionConstant(i-1,j) + *DiffusionConstant(i,j) );
 double Dx_r   = 0.5*( *DiffusionConstant(i+1,j) + *DiffusionConstant(i,j) );
 double Dy_ell = 0.5*( *DiffusionConstant(i,j-1) + *DiffusionConstant(i,j) );
 double Dy_r   = 0.5*( *DiffusionConstant(i,j+1) + *DiffusionConstant(i,j) );
*/ 
 
 double Dx_ell, Dx_r, Dy_ell, Dy_r;
 
 if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
 { 
  if( *Phi(i,j) <= _EPS )
  { Dx_r = InteriorDiffusivity( *X(i) + 0.5*dx , *Y(j) ); }
  else
  { Dx_r = ExteriorDiffusivity( *X(i) + 0.5*dx , *Y(j) ); }
 }
 else
 {
  if( *Phi(i,j) <= _EPS )
  { Dx_r = InteriorDiffusivity( *X(i) , *Y(j) ); }
  else
  { Dx_r = ExteriorDiffusivity( *X(i) , *Y(j) ); }
 }
 
 if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
 { 
  if( *Phi(i,j) <= _EPS )
  { Dx_ell = InteriorDiffusivity( *X(i) - 0.5*dx , *Y(j) ); }
  else
  { Dx_ell = ExteriorDiffusivity( *X(i) - 0.5*dx , *Y(j) ); }
 }
 else
 {
  if( *Phi(i,j) <= _EPS )
  { Dx_ell = InteriorDiffusivity( *X(i) , *Y(j) ); }
  else
  { Dx_ell = ExteriorDiffusivity( *X(i) , *Y(j) ); }
 }
 
 if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
 { 
  if( *Phi(i,j) <= _EPS )
  { Dy_r = InteriorDiffusivity( *X(i), *Y(j) + 0.5*dy); }
  else
  { Dy_r = ExteriorDiffusivity( *X(i), *Y(j) + 0.5*dy ); }
 }
 else
 {
  if( *Phi(i,j) <= _EPS )
  { Dy_r = InteriorDiffusivity( *X(i) , *Y(j) ); }
  else
  { Dy_r = ExteriorDiffusivity( *X(i) , *Y(j) ); }
 }
 
 if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
 { 
  if( *Phi(i,j) <= _EPS )
  { Dy_ell = InteriorDiffusivity( *X(i), *Y(j) - 0.5*dy); }
  else
  { Dy_ell = ExteriorDiffusivity( *X(i), *Y(j) - 0.5*dy ); }
 }
 else
 {
  if( *Phi(i,j) <= _EPS )
  { Dy_ell = InteriorDiffusivity( *X(i) , *Y(j) ); }
  else
  { Dy_ell = ExteriorDiffusivity( *X(i) , *Y(j) ); }
 }
 
 double OutputCoefficientLHS = 1.0/dt; 
 double OutputCoefficientRHS = 0.0;
 double Output = Uij/dt;

 bool DoneX = false;
 bool DoneXleft  = false;
 bool DoneXright = false;
 
 bool DoneY = false;
 bool DoneYleft  = false;
 bool DoneYright = false; 
 
 // do the x-derivative
 // right side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
 {
  Output += *Solution(i+1,j) *Dx_r/dx2; 
  OutputCoefficientRHS -= Dx_r/dx2;
  DoneXright = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i+1,j)) );
//  Theta = 1.0;
  
  double GhostCoefficient = Dx_r/dx2;
  double UinnerCoefficient = 0.0;
  // get ghost point u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i-2,j) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i-2,j)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i-1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneXright = true;
  }				  
  // linear
  if( !DoneXright  )
  { 
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i-1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXright = true;
   }
  }				  
  // constant
  if( !DoneXright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)+Theta*dx , *Y(j) );
  
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)+Theta*dx , *Y(j) ); 
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = InteriorDiffusivity( *X(i)+Theta*dx, *Y(j) );
   Douter = ExteriorDiffusivity( *X(i)+Theta*dx, *Y(j) );
  }
  else
  {
   Dinner = ExteriorDiffusivity( *X(i)+Theta*dx, *Y(j) );
   Douter = InteriorDiffusivity( *X(i)+Theta*dx, *Y(j) );
  }
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0; 
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)+Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
      CompareRegions( *Phi(i+1,j),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS && our_new_method )
  {
   double UxOuter = 2.0-Theta;
   double UyOuter = 0.0;
   double VxOuter = 1.0-Theta;
   double VyOuter = 1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = -(1.0+Theta);
   double UyInner = 0.0;
   double VxInner = -Theta;
   double VyInner = -1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j+2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i+1,j) ) && outer_off_grid )
   {
    double temp_u = *Solution(i+1,j+2)*Theta + *Solution(i+2,j+2)*(1-Theta);
//	BetaOuter *= sqrt( square(1-Theta) + 1 );
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) && outer_on_grid )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i,j-2) , *Phi(i,j) ) && inner_off_grid )
   {
//    BetaInner *= sqrt( square(Theta) + 1 );
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i-1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) && inner_on_grid )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2+Theta)/(1+Theta)
												+*Solution(i-2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						
   DoneXright = true; 
  }

  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+1,j),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i-1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS && our_new_method )
   {
    double UxOuter = 2.0-Theta;
    double UyOuter = 0.0;
    double VxOuter = 1.0-Theta;
    double VyOuter = -1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = -(1.0+Theta);
    double UyInner = 0.0;
    double VxInner = -Theta;
    double VyInner = 1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j-2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i+1,j) ) && outer_off_grid )
   {
    double temp_u = *Solution(i+1,j-2)*Theta + *Solution(i+2,j-2)*(1-Theta);
//	BetaOuter *= sqrt( square(1-Theta) + 1 );
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) && outer_on_grid )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i-1,j+2),*Phi(i,j)) && inner_off_grid )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i-1,j+2)*Theta;
//	BetaInner *= sqrt( square(Theta) + 1.0 );
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0 
							 -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }
   
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) && inner_on_grid )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3.0+2.0*Theta)/( (1.0+Theta)*(2.0+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2.0+Theta)/(1.0+Theta)
												+*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						 
						 
    DoneXright = true; 
   }   
  }
  
  if( !DoneXright && higher_fedkiw && 1 == 1 )
  {
   if( CompareRegions( *Phi(i-2,j), *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i+1,j), *Phi(i+2,j) ) && 
	   CompareRegions( *Phi(i+2,j), *Phi(i+3,j) ) )
   {
	double AlphaOuter = GDP.NormalX;
	double AlphaInner = -GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i+2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i+3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i-1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXright = true;	
   }
  
  }
  
  
  if( !DoneXright && 1 == 0 )
  {
   double s = 1.0;
   if( GDP.NormalX <= _EPS )
   { s *= -1.0; }
  
   if( CompareRegions( *Phi(i,j)   , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) && 1 == 1 )
   {
    *JumpConditionRHS(1) = -dx*NormalDerivativeJump*fabs(GDP.NormalX)/s;
    if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) && higher_fedkiw && 1 == 1 )
    {
     *JumpConditionCoefficientMatrix(1,1) = -(5.0-2.0*Theta)*Douter/((2.0-Theta)*(3.0-Theta));
     *JumpConditionRHS(1) -= Douter*(  *Solution(i+2,j)*(3-Theta)/(2-Theta)
 								        -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
    }
    else
    {
     *JumpConditionCoefficientMatrix(1,1) = -Douter/(2.0-Theta);
	 *JumpConditionRHS(1) -= *Solution(i+2,j)*Douter/(2.0-Theta);
    }
	
    if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) && higher_fedkiw && 1 == 1 )
    {
     *JumpConditionCoefficientMatrix(1,0) = -Dinner*( (3.0+2.0*Theta)/( (1+Theta)*(2+Theta) ) );
 	 *JumpConditionRHS(1) += Dinner*( -*Solution(i-1,j)*(2+Theta)/(1+Theta)
							    	  +*Solution(i-2,j)*(1+Theta)/(2+Theta) );
    }
    else
    {
     *JumpConditionCoefficientMatrix(1,0) = -Dinner/(1.0+Theta);
     *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner/(1.0+Theta);
    }
    DoneXright = true;
   }   
  
  }
  
  if( !DoneXright && 1 == 1 )
  {  
   if( CompareRegions( *Phi(i,j)   , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) && 1 == 1 )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
	 s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
	}
*/ 
    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	

    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                       *Solution(i+2,j)*Douter/(2.0-Theta) + *Solution(i-1,j)*Dinner/(1.0+Theta);
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright && quad )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i+1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i+2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i+3,j));
    DoneXright = true;
   }   
  }
  
  if( !DoneXright && quad )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) && 1 == 1 )
   {
    if( show_message )
    { cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
	
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i-1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i-2,j));	  
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright && lin )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) && 1 == 1 )
   {
    if( show_message )
    { cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i+1,j))
	                     - (1-Theta)*(*Solution(i+2,j));	  
    DoneXright = true; 
   }
  }
  
  if( !DoneXright && lin )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 1 == 1 )
   {
    if( show_message )
    { cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
	
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i-1,j));
    DoneXright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXright )
  {
   if( show_message )
   { cout << __LINE__ << " const " << i << "," << j << endl; }
   Uinner = *Solution(i+1,j) + *JumpConditionRHS(0); 
   DoneXright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 // left side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
 {
  Output += *Solution(i-1,j) *Dx_ell/dx2; 
  OutputCoefficientRHS -= Dx_ell/dx2;
  DoneXleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i-1,j)) );
//  Theta = 1.0;
  
  double GhostCoefficient = Dx_ell/dy2;
  double UinnerCoefficient = 0.0;
  
  // get ghost point u_{i-1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i+2,j) )  )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i+2,j) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i+1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));   
   DoneXleft = true;
  }
  // linear
  if( !DoneXleft  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i+1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXleft = true;
   }
  }				  
  // constant
  if( !DoneXleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)-Theta*dx , *Y(j) );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)-Theta*dx,*Y(j) );
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = InteriorDiffusivity( *X(i)-Theta*dx, *Y(j) );
   Douter = ExteriorDiffusivity( *X(i)-Theta*dx, *Y(j) );
  }
  else
  {
   Dinner = ExteriorDiffusivity( *X(i)-Theta*dx, *Y(j) );
   Douter = InteriorDiffusivity( *X(i)-Theta*dx, *Y(j) );
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)-Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
      CompareRegions( *Phi(i-1,j),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS && our_new_method )
  {
   double UxOuter = -(2.0-Theta);
   double UyOuter = 0.0;
   double VxOuter = -(1.0-Theta);
   double VyOuter = -1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);
   
   double UxInner = (1.0+Theta);
   double UyInner = 0.0;
   double VxInner = Theta;
   double VyInner = 1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i-1,j) ) && outer_off_grid )
   {
    double temp_u = *Solution(i-1,j-2)*Theta + *Solution(i-2,j-2)*(1-Theta);
//	BetaOuter *= sqrt( square(1-Theta) + 1 );
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   

   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) && outer_on_grid )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i+1,j+2),*Phi(i,j)) && inner_off_grid )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i+1,j+2)*Theta;
//	BetaInner *= sqrt( square(Theta) + 1.0 );
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0
							  -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) && inner_on_grid )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }

   DoneXleft = true; 
  }  

  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-1,j),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i+1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS && our_new_method )
   {
    double UxOuter = -(2.0-Theta);
    double UyOuter = 0.0;
    double VxOuter = -(1.0-Theta);
    double VyOuter = 1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = (1.0+Theta);
    double UyInner = 0.0;
    double VxInner = Theta;
    double VyInner = -1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

	*JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j+2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i-1,j) ) && outer_off_grid )
   {
    double temp_u = *Solution(i-1,j+2)*Theta + *Solution(i-2,j+2)*(1-Theta);
//	BetaOuter *= sqrt( square(1-Theta) + 1 );
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   
						   
   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) && outer_on_grid )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i,j-2),*Phi(i,j) ) && 
       CompareRegions( *Phi(i+1,j-2),*Phi(i,j) ) && inner_off_grid )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i+1,j-2)*Theta;
//	BetaInner *= sqrt( square(Theta) + 1.0 );
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
							 -temp_u*0.5 )*Dinner*BetaInner; 
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) && inner_on_grid )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }
						 
    DoneXleft = true; 
   }   
  }
  
  if( !DoneXleft && higher_fedkiw && 1 == 1 )
  {
   if( CompareRegions( *Phi(i+2,j), *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i-1,j), *Phi(i-2,j) ) && 
	   CompareRegions( *Phi(i-2,j), *Phi(i-3,j) ) )
   {
	double AlphaOuter = -GDP.NormalX;
	double AlphaInner = GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i-2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i-3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i+1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i+2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXleft = true;	
   }
  
  }

  if( !DoneXleft && 1 == 0 )
  {
   double s = 1;
   if( GDP.NormalX > _EPS )
   { s *= -1; }
  
   if( CompareRegions( *Phi(i,j)   , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) && 1 == 1 )
   {
    *JumpConditionRHS(1) = -dx*NormalDerivativeJump*fabs(GDP.NormalX)/s;
    if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) && higher_fedkiw && 1 == 1 )
    {
     *JumpConditionCoefficientMatrix(1,1) = -Douter*(5.0-2.0*Theta)/( (2-Theta)*(3-Theta) );
     *JumpConditionRHS(1) += Douter*( -*Solution(i-2,j)*(3-Theta)/(2-Theta)
 								      +*Solution(i-3,j)*(2-Theta)/(3-Theta) );
    }
    else
    {
     *JumpConditionCoefficientMatrix(1,1) = -Douter/(2.0-Theta);
	 *JumpConditionRHS(1) -= *Solution(i-2,j)*Douter/(2.0-Theta);
    }
	
    if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) && higher_fedkiw && 1 == 1 )
    {
     *JumpConditionCoefficientMatrix(1,0) = -Dinner*( (3.0+2.0*Theta)/( (1+Theta)*(2+Theta) ) );
 	 *JumpConditionRHS(1) += Dinner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
									  +*Solution(i+2,j)*(1+Theta)/(2+Theta) );
    }
    else
    {
     *JumpConditionCoefficientMatrix(1,0) = -Dinner/(1.0+Theta);
     *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner/(1.0+Theta);
    }
    DoneXleft = true;
   }   
  
  }
  
  if( !DoneXleft && 1 == 1 )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) && 1 == 1 )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1 )
	{
     s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
    }
*/

    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	
	
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                     *Solution(i-2,j)*Douter/(2.0-Theta) + *Solution(i+1,j)*Dinner/(1.0+Theta);
    DoneXleft = true; 
   }
  }  
  
  
  if( !DoneXleft && quad )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) && 1 == 1 )
   {
    if( show_message )
    { cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }

    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i-1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i-2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i-3,j));
    DoneXleft = true;
   }   
  }
  
  if( !DoneXleft && quad )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) && 1 == 1 )
   {
    if( show_message )
    { cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i+1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i+2,j));	  
    DoneXleft = true; 
   }
  }   
  
  if( !DoneXleft && lin )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) && 1 == 1 )
   {
    if( show_message )
    { cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i-1,j))
	                     - (1-Theta)*(*Solution(i-2,j));	  
    DoneXleft = true; 
   }
  }
  
  if( !DoneXleft && lin )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 1 == 1 )
   {
    if( show_message )
    { cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i+1,j));
    DoneXleft = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXleft )
  {
   if( show_message )
   { cout << __LINE__ << " const " << i << "," << j << endl; }
   Uinner = *Solution(i-1,j) + *JumpConditionRHS(0); 
   DoneXleft = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // do the y-derivative
 // right side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) )  )
 {
  Output += *Solution(i,j+1) *Dy_r/dy2; 
  OutputCoefficientRHS -= Dy_r/dy2;
  DoneYright = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j+1)) );
//  Theta = 1.0;
  double GhostCoefficient = Dy_r/dy2;
  double UinnerCoefficient = 0.0;
  // get ghost phone u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i,j-2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j-2)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j-1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneYright = true;
  }				  
  // linear
  if( !DoneYright  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j-1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYright = true;
   }
  }				  
  // constant
  if( !DoneYright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)+Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i) , *Y(j)+Theta*dy );
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = InteriorDiffusivity( *X(i),*Y(j)+Theta*dy );
   Douter = ExteriorDiffusivity( *X(i),*Y(j)+Theta*dy );
  }
  else
  {
   Dinner = ExteriorDiffusivity( *X(i),*Y(j)+Theta*dy );
   Douter = InteriorDiffusivity( *X(i),*Y(j)+Theta*dy );
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;  
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)+Theta*dy);
  
  if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
      CompareRegions( *Phi(i,j+1),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS && our_new_method )
  {
   double UxOuter = 0.0;
   double UyOuter = 2.0-Theta;
   double VxOuter = 1.0;
   double VyOuter = 1.0-Theta;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = -(1.0+Theta);
   double VxInner = -1.0;
   double VyInner = -Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i,j+1) ) && outer_off_grid )
   {
    double temp_u = *Solution(i+2,j+1)*Theta + *Solution(i+2,j+2)*(1-Theta);
//	BetaOuter *= sqrt( square(1-Theta) + 1 );
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) && outer_on_grid )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i-2,j) , *Phi(i,j) ) && inner_off_grid )
   {
//    BetaInner *= sqrt( square(Theta) + 1 );
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j-1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) && inner_on_grid )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }

						
   DoneYright = true; 
  }  

  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+1),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j-1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS && our_new_method )
   {
    double UxOuter = 0.0;
    double UyOuter = 2.0-Theta;
    double VxOuter = -1.0;
    double VyOuter = 1.0-Theta;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = -(1.0+Theta);
    double VxInner = 1.0;
    double VyInner = -Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i,j+1) ) && outer_off_grid )
   {
    double temp_u = *Solution(i-2,j+1)*Theta + *Solution(i-2,j+2)*(1-Theta);
//	BetaOuter *= sqrt( square(1-Theta) + 1 );
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) && outer_on_grid )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i+2,j) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i+2,j-1) , *Phi(i,j) ) && inner_off_grid )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j-1)*Theta;
//	BetaInner *= sqrt( square(Theta) + 1.0 );
	
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 
						     -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) && inner_on_grid )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }
						 
    DoneYright = true; 
   }   
  }
  
  if( !DoneYright && higher_fedkiw && 1 == 1 )
  {
   if( CompareRegions( *Phi(i,j-2), *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j+1), *Phi(i,j+2) ) && 
	   CompareRegions( *Phi(i,j+2), *Phi(i,j+3) ) )
   {
	double AlphaOuter = GDP.NormalY;
	double AlphaInner = -GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j+2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j+3)*(2.0-Theta)/(3.0-Theta));
	*JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j-1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j-2)*(1.0+Theta)/(2.0+Theta));
												
    DoneYright = true;									 
   }
  
  }
  
  
  if( !DoneYright && 1 == 0 )
  {
   double s = 1.0;
   if( GDP.NormalY <= _EPS )
   { s *= -1.0; }
  
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) && 1 == 1 )
   {
    *JumpConditionRHS(1) = -dy*NormalDerivativeJump*fabs(GDP.NormalY)/s;
    if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) && higher_fedkiw && 1 == 1 )
    {
     *JumpConditionCoefficientMatrix(1,1) = -(5.0-2.0*Theta)*Douter/((2.0-Theta)*(3.0-Theta));
     *JumpConditionRHS(1) -= Douter*(  *Solution(i,j+2)*(3-Theta)/(2-Theta)
 								      -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
    }
    else
    {
     *JumpConditionCoefficientMatrix(1,1) = -Douter/(2.0-Theta);
	 *JumpConditionRHS(1) -= *Solution(i,j+2)*Douter/(2.0-Theta);
    }
	
    if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) && higher_fedkiw && 1 == 1 )
    {
     *JumpConditionCoefficientMatrix(1,0) = -Dinner*( (3.0+2.0*Theta)/( (1+Theta)*(2+Theta) ) );
 	 *JumpConditionRHS(1) += Dinner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
							    	  +*Solution(i,j-2)*(1+Theta)/(2+Theta) );
    }
    else
    {
     *JumpConditionCoefficientMatrix(1,0) = -Dinner/(1.0+Theta);
     *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner/(1.0+Theta);
    }
    DoneYright = true;
   }   
  
  }
  
  if( !DoneYright && 1 == 1 )
  {
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) && 1 == 1 )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
     s = 1;
	 if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                       *Solution(i,j+2)*Douter/(2.0-Theta) + *Solution(i,j-1)*Dinner/(1.0+Theta);
    DoneYright = true; 
   }  
  }
  
  
  if( !DoneYright && quad )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }

    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j+1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j+2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j+3));
    DoneYright = true;
   }   
  }
  
  if( !DoneYright && quad )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j-1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j-2));	  
    DoneYright = true; 
   }
  }   
  
  if( !DoneYright && lin )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j+1))
	                     - (1-Theta)*(*Solution(i,j+2));	  
    DoneYright = true; 
   }
  }
  
  if( !DoneYright && lin )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j-1));
    DoneYright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYright )
  {
   if( show_message )
   { cout << __LINE__ << " const " << i << "," << j << endl; }
  
   Uinner = *Solution(i,j+1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // left side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
 {
  Output += *Solution(i,j-1) *Dy_ell/dy2; 
  OutputCoefficientRHS -= Dy_ell/dy2;
  DoneYleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j-1)) );
//  Theta = 1.0;
  double GhostCoefficient = Dy_ell/dy2;
  double UinnerCoefficient = 0.0;

  // get ghost phone u_{i-1}
  // quadratic
  if( !DoneYleft && CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) 
                 && CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j+2) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j+1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));     
   DoneYleft = true;
  }				  
  // linear
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j+1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYleft = true;
   }
  }				  
  // constant
  if( !DoneYleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)-Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i),*Y(j)-Theta*dy);
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = InteriorDiffusivity( *X(i),*Y(j)-Theta*dy );
   Douter = ExteriorDiffusivity( *X(i),*Y(j)-Theta*dy );
  }
  else
  {
   Dinner = ExteriorDiffusivity( *X(i),*Y(j)-Theta*dy );
   Douter = InteriorDiffusivity( *X(i),*Y(j)-Theta*dy );
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;   
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)-Theta*dy);
  
  if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
      CompareRegions( *Phi(i,j-1),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS && our_new_method )
  {
   double UxOuter = 0.0;
   double UyOuter = -(2.0-Theta);
   double VxOuter = -1.0;
   double VyOuter = -(1.0-Theta);
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = 1.0+Theta;
   double VxInner = 1.0;
   double VyInner = Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i,j-1) ) && outer_off_grid )
   {
    double temp_u = *Solution(i-2,j-1)*Theta + *Solution(i-2,j-2)*(1-Theta);
//	BetaOuter *= sqrt( square(1-Theta) + 1 );
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) && outer_on_grid )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i+2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i+2,j+1),*Phi(i,j)) && inner_off_grid )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j+1)*Theta;
//	BetaInner *= sqrt( square(Theta) + 1.0 );
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) && inner_on_grid )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						
   DoneYleft = true; 
  }  

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-1),*Phi(i+1,j-1) ) && // typo this line: (i+1,j+1)
 	   CompareRegions( *Phi(i,j),*Phi(i,j+1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS && our_new_method )
   {
    double UxOuter = 0.0;
    double UyOuter = -(2.0-Theta);
    double VxOuter = 1.0;
    double VyOuter = -(1.0-Theta);
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = 1.0+Theta;
    double VxInner = -1.0;
    double VyInner = Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i,j-1) ) && outer_off_grid )
   {
    double temp_u = *Solution(i+2,j-1)*Theta + *Solution(i+2,j-2)*(1-Theta);
//	BetaOuter *= sqrt( square(1-Theta) + 1 );
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) && outer_on_grid )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i-2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i-2,j+1),*Phi(i,j)) && inner_off_grid )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j+1)*Theta;
//	BetaInner *= sqrt( square(Theta) + 1.0 );
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {   
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }	
	
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) && inner_on_grid )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						 
    DoneYleft = true; 
   }   
  }  
  
  if( !DoneYleft && higher_fedkiw && 1 == 1 )
  {
   if( CompareRegions( *Phi(i,j+2), *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j+1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j-1), *Phi(i,j-2) ) && 
	   CompareRegions( *Phi(i,j-2), *Phi(i,j-3) ) )
   {
	double AlphaOuter = -GDP.NormalY;
	double AlphaInner = GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j-2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j-3)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j+1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j+2)*(1.0+Theta)/(2.0+Theta));
	
    DoneYleft = true;									 
   }
  
  }  
  
  
  if( !DoneYleft && 1 == 0 )
  {
   double s = 1;
   if( GDP.NormalY > _EPS )
   { s *= -1; }
  
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) && 1 == 1 )
   {
    *JumpConditionRHS(1) = -dy*NormalDerivativeJump*fabs(GDP.NormalY)/s;
    if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) && higher_fedkiw && 1 == 1 )
    {
     *JumpConditionCoefficientMatrix(1,1) = -Douter*(5.0-2.0*Theta)/( (2-Theta)*(3-Theta) );
     *JumpConditionRHS(1) += Douter*( -*Solution(i,j-2)*(3-Theta)/(2-Theta)
 								      +*Solution(i,j-3)*(2-Theta)/(3-Theta) );
    }
    else
    {
     *JumpConditionCoefficientMatrix(1,1) = -Douter/(2.0-Theta);
	 *JumpConditionRHS(1) -= *Solution(i,j-2)*Douter/(2.0-Theta);
    }
	
    if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) && higher_fedkiw && 1 == 1 )
    {
     *JumpConditionCoefficientMatrix(1,0) = -Dinner*( (3.0+2.0*Theta)/( (1+Theta)*(2+Theta) ) );
 	 *JumpConditionRHS(1) += Dinner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
									  +*Solution(i,j+2)*(1+Theta)/(2+Theta) );
    }
    else
    {
     *JumpConditionCoefficientMatrix(1,0) = -Dinner/(1.0+Theta);
     *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner/(1.0+Theta);
    }
    DoneYleft = true;
   }    
 
  }  
  
  if( !DoneYleft && 1 == 1 )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) && 1 == 1 )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
 	 s = 1;
     if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) =Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                     *Solution(i,j-2)*Douter/(2.0-Theta) + *Solution(i,j+1)*Dinner/(1.0+Theta);
    DoneYleft = true; 
   }  
  } 
 

  if( !DoneYleft && quad )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j-1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j-2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j-3));
    DoneYleft = true;
   }   
  }
  
  if( !DoneYleft && quad )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j+1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j+2));	  
    DoneYleft = true; 
   }
  }   
  
  if( !DoneYleft && lin )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j-1))
	                     - (1-Theta)*(*Solution(i,j-2));	  
    DoneYleft = true; 
   }
  }
  
  if( !DoneYleft && lin )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 1 == 1 )
   {
    if( show_message )
	{ cout << __LINE__ << " " << *X(i) << "," << *Y(j) << endl; }
   
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j+1));
    DoneYleft = true;
   }
  }

  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYleft )
  {
   if( show_message )
   { cout << __LINE__ << " const " << i << "," << j << endl; }
  
   Uinner = *Solution(i,j-1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 if( DoneXright && DoneXleft )
 { DoneX = true; }
 if( DoneYright && DoneYleft )
 { DoneY = true; }
 
 // add a non-diffusion case here
 if( !DoneX && !DoneY ) 
 {  
  Output += ( *Solution(i-1,j) * Dx_ell + *Solution(i+1,j) *Dx_r )/dx2;
  Output += ( *Solution(i,j-1) * Dy_ell + *Solution(i,j+1) *Dy_r )/dy2;
  OutputCoefficientRHS -= ( (Dx_ell+Dx_r)/dx2 + (Dy_ell+Dy_r)/dy2 );         
 }
 
 // source 
 OutputCoefficientRHS += *SourceFunctionU(i,j);
 Output += *SourceFunction(i,j);
 Output /= (OutputCoefficientLHS-OutputCoefficientRHS);
 
 return Output; 
}   

double gfmImplicitUpdateDiscontinuousD( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   double(*InteriorDiffusivity)(double,double),
   double(*ExteriorDiffusivity)(double,double),
   Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy )
{
 extern double _EPS;

 double Uij = *Solution(i,j);
 double dt = 1;
 double dx2 = square(dx);
 double dy2 = square(dy);
 
 double Dx_ell, Dx_r, Dy_ell, Dy_r;
 
 // Compute the centered diffusivities. For now, use constant extrapolations 
 // for the diffusivities. 
 
 if( *Phi(i,j) <= _EPS )
 {
  if( CompareRegions( *Phi(i,j),*Phi(i+1,j) ) )
  { Dx_r = InteriorDiffusivity(*X(i)+0.5*dx,*Y(j)); }
  else
  { Dx_r = InteriorDiffusivity(*X(i),*Y(j)); }
  
  if( CompareRegions( *Phi(i,j),*Phi(i-1,j) ) )
  { Dx_ell = InteriorDiffusivity(*X(i)-0.5*dx,*Y(j)); }
  else
  { Dx_ell = InteriorDiffusivity(*X(i),*Y(j)); }
 
  if( CompareRegions( *Phi(i,j),*Phi(i,j+1) ) )
  { Dy_r = InteriorDiffusivity(*X(i),*Y(j)+0.5*dy); }
  else
  { Dy_r = InteriorDiffusivity(*X(i),*Y(j)); }
  
  if( CompareRegions( *Phi(i,j),*Phi(i,j-1) ) )
  { Dy_ell = InteriorDiffusivity(*X(i),*Y(j)-0.5*dy); }
  else
  { Dy_ell = InteriorDiffusivity(*X(i),*Y(j)); }
 }
 else
 {
  if( CompareRegions( *Phi(i,j),*Phi(i+1,j) ) )
  { Dx_r = ExteriorDiffusivity(*X(i)+0.5*dx,*Y(j)); }
  else
  { Dx_r = ExteriorDiffusivity(*X(i),*Y(j)); }
  
  if( CompareRegions( *Phi(i,j),*Phi(i-1,j) ) )
  { Dx_ell = ExteriorDiffusivity(*X(i)-0.5*dx,*Y(j)); }
  else
  { Dx_ell = ExteriorDiffusivity(*X(i),*Y(j)); }
 
  if( CompareRegions( *Phi(i,j),*Phi(i,j+1) ) )
  { Dy_r = ExteriorDiffusivity(*X(i),*Y(j)+0.5*dy); }
  else
  { Dy_r = ExteriorDiffusivity(*X(i),*Y(j)); }
  
  if( CompareRegions( *Phi(i,j),*Phi(i,j-1) ) )
  { Dy_ell = ExteriorDiffusivity(*X(i),*Y(j)-0.5*dy); }
  else
  { Dy_ell = ExteriorDiffusivity(*X(i),*Y(j)); }
 }
 
 double OutputCoefficientLHS = 1.0/dt; 
 double OutputCoefficientRHS = 0.0;
 double Output = Uij/dt;

 bool DoneX = false;
 bool DoneXleft  = false;
 bool DoneXright = false;
 
 bool DoneY = false;
 bool DoneYleft  = false;
 bool DoneYright = false; 
 
 // do the x-derivative
 // right side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
 {
  Output += *Solution(i+1,j) *Dx_r/dx2; 
  OutputCoefficientRHS -= Dx_r/dx2;
  DoneXright = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i+1,j)) );
  
  double GhostCoefficient = Dx_r/dx2;
  double UinnerCoefficient = 0.0;
  // get ghost point u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i-2,j) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i-2,j)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i-1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneXright = true;
  }				  
  // linear
  if( !DoneXright  )
  { 
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i-1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXright = true;
   }
  }				  
  // constant
  if( !DoneXright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)+Theta*dx , *Y(j) );
  
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)+Theta*dx , *Y(j) ); 
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = InteriorDiffusivity( *X(i)+Theta*dx, *Y(j) );
   Douter = ExteriorDiffusivity( *X(i)+Theta*dx, *Y(j) );
  }
  else
  {
   Dinner = ExteriorDiffusivity( *X(i)+Theta*dx, *Y(j) );
   Douter = InteriorDiffusivity( *X(i)+Theta*dx, *Y(j) );
  }
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0; 
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)+Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
      CompareRegions( *Phi(i+1,j),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 2.0-Theta;
   double UyOuter = 0.0;
   double VxOuter = 1.0-Theta;
   double VyOuter = 1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = -(1.0+Theta);
   double UyInner = 0.0;
   double VxInner = -Theta;
   double VyInner = -1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j+2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i+1,j) ) )
   {
    double temp_u = *Solution(i+1,j+2)*Theta + *Solution(i+2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i,j-2) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i-1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2+Theta)/(1+Theta)
												+*Solution(i-2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						
   DoneXright = true; 
  }

  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+1,j),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i-1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 2.0-Theta;
    double UyOuter = 0.0;
    double VxOuter = 1.0-Theta;
    double VyOuter = -1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = -(1.0+Theta);
    double UyInner = 0.0;
    double VxInner = -Theta;
    double VyInner = 1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j-2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i+1,j) ) )
   {
    double temp_u = *Solution(i+1,j-2)*Theta + *Solution(i+2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i-1,j+2),*Phi(i,j)) )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i-1,j+2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0 
							 -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }
   
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3.0+2.0*Theta)/( (1.0+Theta)*(2.0+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2.0+Theta)/(1.0+Theta)
												+*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						 
    DoneXright = true; 
   }   
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i-2,j), *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i+1,j), *Phi(i+2,j) ) && 
	   CompareRegions( *Phi(i+2,j), *Phi(i+3,j) ) )
   {
	double AlphaOuter = GDP.NormalX;
	double AlphaInner = -GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i+2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i+3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i-1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXright = true;	
   }
  
  }
  
  if( !DoneXright )
  {  
   if( CompareRegions( *Phi(i,j)   , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
	 s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
	}
*/ 
    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	

    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                       *Solution(i+2,j)*Douter/(2.0-Theta) + *Solution(i-1,j)*Dinner/(1.0+Theta);
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i+1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i+2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i+3,j));
    DoneXright = true;
   }   
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i-1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i-2,j));	  
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i+1,j))
	                     - (1-Theta)*(*Solution(i+2,j));	  
    DoneXright = true; 
   }
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i-1,j));
    DoneXright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXright )
  {
   Uinner = *Solution(i+1,j) + *JumpConditionRHS(0); 
   DoneXright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 // left side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
 {
  Output += *Solution(i-1,j) *Dx_ell/dx2; 
  OutputCoefficientRHS -= Dx_ell/dx2;
  DoneXleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i-1,j)) );
  
  double GhostCoefficient = Dx_ell/dy2;
  double UinnerCoefficient = 0.0;
  
  // get ghost point u_{i-1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i+2,j) )  )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i+2,j) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i+1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));   
   DoneXleft = true;
  }
  // linear
  if( !DoneXleft  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i+1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXleft = true;
   }
  }				  
  // constant
  if( !DoneXleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)-Theta*dx , *Y(j) );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)-Theta*dx,*Y(j) );
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = InteriorDiffusivity( *X(i)-Theta*dx, *Y(j) );
   Douter = ExteriorDiffusivity( *X(i)-Theta*dx, *Y(j) );
  }
  else
  {
   Dinner = ExteriorDiffusivity( *X(i)-Theta*dx, *Y(j) );
   Douter = InteriorDiffusivity( *X(i)-Theta*dx, *Y(j) );
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)-Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
      CompareRegions( *Phi(i-1,j),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = -(2.0-Theta);
   double UyOuter = 0.0;
   double VxOuter = -(1.0-Theta);
   double VyOuter = -1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);
   
   double UxInner = (1.0+Theta);
   double UyInner = 0.0;
   double VxInner = Theta;
   double VyInner = 1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i-1,j) ) )
   {
    double temp_u = *Solution(i-1,j-2)*Theta + *Solution(i-2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   

   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i+1,j+2),*Phi(i,j)) )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i+1,j+2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0
							  -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }

   DoneXleft = true; 
  }  

  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-1,j),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i+1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = -(2.0-Theta);
    double UyOuter = 0.0;
    double VxOuter = -(1.0-Theta);
    double VyOuter = 1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = (1.0+Theta);
    double UyInner = 0.0;
    double VxInner = Theta;
    double VyInner = -1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

	*JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j+2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i-1,j) ) )
   {
    double temp_u = *Solution(i-1,j+2)*Theta + *Solution(i-2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   
						   
   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i,j-2),*Phi(i,j) ) && 
       CompareRegions( *Phi(i+1,j-2),*Phi(i,j) ) )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i+1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
							 -temp_u*0.5 )*Dinner*BetaInner; 
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }
						 
    DoneXleft = true; 
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i+2,j), *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i-1,j), *Phi(i-2,j) ) && 
	   CompareRegions( *Phi(i-2,j), *Phi(i-3,j) ) )
   {
	double AlphaOuter = -GDP.NormalX;
	double AlphaInner = GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i-2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i-3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i+1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i+2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXleft = true;	
   }
  
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1 )
	{
     s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
    }
*/

    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	
	
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                     *Solution(i-2,j)*Douter/(2.0-Theta) + *Solution(i+1,j)*Dinner/(1.0+Theta);
    DoneXleft = true; 
   }
  }  
  
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i-1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i-2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i-3,j));
    DoneXleft = true;
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i+1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i+2,j));	  
    DoneXleft = true; 
   }
  }   
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i-1,j))
	                     - (1-Theta)*(*Solution(i-2,j));	  
    DoneXleft = true; 
   }
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i+1,j));
    DoneXleft = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXleft )
  {
   Uinner = *Solution(i-1,j) + *JumpConditionRHS(0); 
   DoneXleft = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // do the y-derivative
 // right side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) )  )
 {
  Output += *Solution(i,j+1) *Dy_r/dy2; 
  OutputCoefficientRHS -= Dy_r/dy2;
  DoneYright = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j+1)) );

  double GhostCoefficient = Dy_r/dy2;
  double UinnerCoefficient = 0.0;
  // get ghost phone u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i,j-2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j-2)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j-1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneYright = true;
  }				  
  // linear
  if( !DoneYright  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j-1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYright = true;
   }
  }				  
  // constant
  if( !DoneYright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)+Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i) , *Y(j)+Theta*dy );
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = InteriorDiffusivity( *X(i),*Y(j)+Theta*dy );
   Douter = ExteriorDiffusivity( *X(i),*Y(j)+Theta*dy );
  }
  else
  {
   Dinner = ExteriorDiffusivity( *X(i),*Y(j)+Theta*dy );
   Douter = InteriorDiffusivity( *X(i),*Y(j)+Theta*dy );
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;  
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)+Theta*dy);
  
  if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
      CompareRegions( *Phi(i,j+1),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = 2.0-Theta;
   double VxOuter = 1.0;
   double VyOuter = 1.0-Theta;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = -(1.0+Theta);
   double VxInner = -1.0;
   double VyInner = -Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i,j+1) ) )
   {
    double temp_u = *Solution(i+2,j+1)*Theta + *Solution(i+2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i-2,j) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j-1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }

   DoneYright = true; 
  }  

  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+1),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j-1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = 2.0-Theta;
    double VxOuter = -1.0;
    double VyOuter = 1.0-Theta;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = -(1.0+Theta);
    double VxInner = 1.0;
    double VyInner = -Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i,j+1) ) )
   {
    double temp_u = *Solution(i-2,j+1)*Theta + *Solution(i-2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i+2,j) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i+2,j-1) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j-1)*Theta;
	
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 
						     -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }
						 
    DoneYright = true; 
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j-2), *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j+1), *Phi(i,j+2) ) && 
	   CompareRegions( *Phi(i,j+2), *Phi(i,j+3) ) )
   {
	double AlphaOuter = GDP.NormalY;
	double AlphaInner = -GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j+2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j+3)*(2.0-Theta)/(3.0-Theta));
	*JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j-1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j-2)*(1.0+Theta)/(2.0+Theta));
												
    DoneYright = true;									 
   }
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
     s = 1;
	 if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                       *Solution(i,j+2)*Douter/(2.0-Theta) + *Solution(i,j-1)*Dinner/(1.0+Theta);
    DoneYright = true; 
   }  
  }
  
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j+1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j+2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j+3));
    DoneYright = true;
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j-1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j-2));	  
    DoneYright = true; 
   }
  }   
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j+1))
	                     - (1-Theta)*(*Solution(i,j+2));	  
    DoneYright = true; 
   }
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j-1));
    DoneYright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYright )
  {
   Uinner = *Solution(i,j+1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // left side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
 {
  Output += *Solution(i,j-1) *Dy_ell/dy2; 
  OutputCoefficientRHS -= Dy_ell/dy2;
  DoneYleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j-1)) );

  double GhostCoefficient = Dy_ell/dy2;
  double UinnerCoefficient = 0.0;

  // get ghost phone u_{i-1}
  // quadratic
  if( !DoneYleft && CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) 
                 && CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j+2) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j+1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));     
   DoneYleft = true;
  }				  
  // linear
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j+1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYleft = true;
   }
  }				  
  // constant
  if( !DoneYleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)-Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i),*Y(j)-Theta*dy);
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = InteriorDiffusivity( *X(i),*Y(j)-Theta*dy );
   Douter = ExteriorDiffusivity( *X(i),*Y(j)-Theta*dy );
  }
  else
  {
   Dinner = ExteriorDiffusivity( *X(i),*Y(j)-Theta*dy );
   Douter = InteriorDiffusivity( *X(i),*Y(j)-Theta*dy );
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;   
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)-Theta*dy);
  
  if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
      CompareRegions( *Phi(i,j-1),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = -(2.0-Theta);
   double VxOuter = -1.0;
   double VyOuter = -(1.0-Theta);
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = 1.0+Theta;
   double VxInner = 1.0;
   double VyInner = Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i,j-1) ) )
   {
    double temp_u = *Solution(i-2,j-1)*Theta + *Solution(i-2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i+2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i+2,j+1),*Phi(i,j)) )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j+1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						
   DoneYleft = true; 
  }  

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-1),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j+1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = -(2.0-Theta);
    double VxOuter = 1.0;
    double VyOuter = -(1.0-Theta);
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = 1.0+Theta;
    double VxInner = -1.0;
    double VyInner = Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i,j-1) ) )
   {
    double temp_u = *Solution(i+2,j-1)*Theta + *Solution(i+2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i-2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i-2,j+1),*Phi(i,j)) )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j+1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {   
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }	
	
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						 
    DoneYleft = true; 
   }   
  }  
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j+2), *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j+1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j-1), *Phi(i,j-2) ) && 
	   CompareRegions( *Phi(i,j-2), *Phi(i,j-3) ) )
   {
	double AlphaOuter = -GDP.NormalY;
	double AlphaInner = GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j-2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j-3)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j+1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j+2)*(1.0+Theta)/(2.0+Theta));
	
    DoneYleft = true;									 
   }
  
  }  
  
  if( !DoneYleft )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
 	 s = 1;
     if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) =Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                     *Solution(i,j-2)*Douter/(2.0-Theta) + *Solution(i,j+1)*Dinner/(1.0+Theta);
    DoneYleft = true; 
   }  
  } 
 

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j-1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j-2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j-3));
    DoneYleft = true;
   }   
  }
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j+1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j+2));	  
    DoneYleft = true; 
   }
  }   
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j-1))
	                     - (1-Theta)*(*Solution(i,j-2));	  
    DoneYleft = true; 
   }
  }
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j+1));
    DoneYleft = true;
   }
  }

  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYleft )
  {
   Uinner = *Solution(i,j-1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 if( DoneXright && DoneXleft )
 { DoneX = true; }
 if( DoneYright && DoneYleft )
 { DoneY = true; }
 
 // add a non-diffusion case here
 if( !DoneX && !DoneY ) 
 {  
  Output += ( *Solution(i-1,j) * Dx_ell + *Solution(i+1,j) *Dx_r )/dx2;
  Output += ( *Solution(i,j-1) * Dy_ell + *Solution(i,j+1) *Dy_r )/dy2;
  OutputCoefficientRHS -= ( (Dx_ell+Dx_r)/dx2 + (Dy_ell+Dy_r)/dy2 );         
 }
 
 // source 
 OutputCoefficientRHS += *SourceFunctionU(i,j);
 Output += *SourceFunction(i,j);
 Output /= (OutputCoefficientLHS-OutputCoefficientRHS);
 
 return Output; 
}   

double gfmImplicitUpdateDiscontinuousD_MatrixForm( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   Matrix& InteriorDiffusivity,
   Matrix& ExteriorDiffusivity,
   Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy )
{
 extern double _EPS;

 double Uij = *Solution(i,j);
 double dt = 1;
 double dx2 = square(dx);
 double dy2 = square(dy);

/*
 double Dx_ell = 0.5*( *DiffusionConstant(i-1,j) + *DiffusionConstant(i,j) );
 double Dx_r   = 0.5*( *DiffusionConstant(i+1,j) + *DiffusionConstant(i,j) );
 double Dy_ell = 0.5*( *DiffusionConstant(i,j-1) + *DiffusionConstant(i,j) );
 double Dy_r   = 0.5*( *DiffusionConstant(i,j+1) + *DiffusionConstant(i,j) );
 
 double Dx_ell = 0.5*( *DiffusionConstant(i-1,j) + *DiffusionConstant(i,j) );
 double Dx_r   = 0.5*( *DiffusionConstant(i+1,j) + *DiffusionConstant(i,j) );
 double Dy_ell = 0.5*( *DiffusionConstant(i,j-1) + *DiffusionConstant(i,j) );
 double Dy_r   = 0.5*( *DiffusionConstant(i,j+1) + *DiffusionConstant(i,j) );
*/ 
 
 double Dx_ell, Dx_r, Dy_ell, Dy_r;
 
 // Compute the centered diffusivities. For now, use constant extrapolations 
 // for the diffusivities. 
 
 if( *Phi(i,j) <= _EPS )
 {
  if( CompareRegions( *Phi(i,j),*Phi(i+1,j) ) )
  { Dx_r = 0.5*( *InteriorDiffusivity(i,j) + *InteriorDiffusivity(i+1,j) ); }
  else
  { Dx_r = *InteriorDiffusivity(i,j); }
  
  if( CompareRegions( *Phi(i,j),*Phi(i-1,j) ) )
  { Dx_ell = 0.5*( *InteriorDiffusivity(i,j) + *InteriorDiffusivity(i-1,j) ); }
  else
  { Dx_ell = *InteriorDiffusivity(i,j); }
 
  if( CompareRegions( *Phi(i,j),*Phi(i,j+1) ) )
  { Dy_r = 0.5*( *InteriorDiffusivity(i,j) + *InteriorDiffusivity(i,j+1) ); }
  else
  { Dy_r = *InteriorDiffusivity(i,j); }
  
  if( CompareRegions( *Phi(i,j),*Phi(i,j-1) ) )
  { Dy_ell = 0.5*( *InteriorDiffusivity(i,j) + *InteriorDiffusivity(i,j-1) ); }
  else
  { Dy_ell = *InteriorDiffusivity(i,j); }
 }
 else
 {
  if( CompareRegions( *Phi(i,j),*Phi(i+1,j) ) )
  { Dx_r = 0.5*( *ExteriorDiffusivity(i,j) + *ExteriorDiffusivity(i+1,j) ); }
  else
  { Dx_r = *ExteriorDiffusivity(i,j); }
  
  if( CompareRegions( *Phi(i,j),*Phi(i-1,j) ) )
  { Dx_ell = 0.5*( *ExteriorDiffusivity(i,j) + *ExteriorDiffusivity(i-1,j) ); }
  else
  { Dx_ell = *ExteriorDiffusivity(i,j); }
 
  if( CompareRegions( *Phi(i,j),*Phi(i,j+1) ) )
  { Dy_r = 0.5*( *ExteriorDiffusivity(i,j) + *ExteriorDiffusivity(i,j+1) ); }
  else
  { Dy_r = *ExteriorDiffusivity(i,j); }
  
  if( CompareRegions( *Phi(i,j),*Phi(i,j-1) ) )
  { Dy_ell = 0.5*( *ExteriorDiffusivity(i,j) + *ExteriorDiffusivity(i,j-1) ); }
  else
  { Dy_ell = *ExteriorDiffusivity(i,j); }
 }
 
 double OutputCoefficientLHS = 1.0/dt; 
 double OutputCoefficientRHS = 0.0;
 double Output = Uij/dt;

 bool DoneX = false;
 bool DoneXleft  = false;
 bool DoneXright = false;
 
 bool DoneY = false;
 bool DoneYleft  = false;
 bool DoneYright = false; 
 
 // do the x-derivative
 // right side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
 {
  Output += *Solution(i+1,j) *Dx_r/dx2; 
  OutputCoefficientRHS -= Dx_r/dx2;
  DoneXright = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i+1,j)) );
  
  double GhostCoefficient = Dx_r/dx2;
  double UinnerCoefficient = 0.0;
  // get ghost point u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i-2,j) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i-2,j)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i-1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneXright = true;
  }				  
  // linear
  if( !DoneXright  )
  { 
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i-1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXright = true;
   }
  }				  
  // constant
  if( !DoneXright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)+Theta*dx , *Y(j) );
  
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)+Theta*dx , *Y(j) ); 
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = *InteriorDiffusivity(i,j);
   Douter = *ExteriorDiffusivity(i+1,j);
  }
  else
  {
   Dinner = *ExteriorDiffusivity(i,j);
   Douter = *InteriorDiffusivity(i+1,j);
  }
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0; 
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)+Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
      CompareRegions( *Phi(i+1,j),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 2.0-Theta;
   double UyOuter = 0.0;
   double VxOuter = 1.0-Theta;
   double VyOuter = 1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = -(1.0+Theta);
   double UyInner = 0.0;
   double VxInner = -Theta;
   double VyInner = -1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j+2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i+1,j) ) )
   {
    double temp_u = *Solution(i+1,j+2)*Theta + *Solution(i+2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i,j-2) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i-1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2+Theta)/(1+Theta)
												+*Solution(i-2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						
   DoneXright = true; 
  }

  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+1,j),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i-1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 2.0-Theta;
    double UyOuter = 0.0;
    double VxOuter = 1.0-Theta;
    double VyOuter = -1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = -(1.0+Theta);
    double UyInner = 0.0;
    double VxInner = -Theta;
    double VyInner = 1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j-2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i+1,j) ) )
   {
    double temp_u = *Solution(i+1,j-2)*Theta + *Solution(i+2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i-1,j+2),*Phi(i,j)) )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i-1,j+2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0 
							 -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }
   
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3.0+2.0*Theta)/( (1.0+Theta)*(2.0+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2.0+Theta)/(1.0+Theta)
												+*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						 
    DoneXright = true; 
   }   
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i-2,j), *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i+1,j), *Phi(i+2,j) ) && 
	   CompareRegions( *Phi(i+2,j), *Phi(i+3,j) ) )
   {
	double AlphaOuter = GDP.NormalX;
	double AlphaInner = -GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i+2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i+3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i-1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXright = true;	
   }
  
  }
  
  if( !DoneXright )
  {  
   if( CompareRegions( *Phi(i,j)   , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
	 s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
	}
*/ 
    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	

    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                       *Solution(i+2,j)*Douter/(2.0-Theta) + *Solution(i-1,j)*Dinner/(1.0+Theta);
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i+1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i+2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i+3,j));
    DoneXright = true;
   }   
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i-1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i-2,j));	  
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i+1,j))
	                     - (1-Theta)*(*Solution(i+2,j));	  
    DoneXright = true; 
   }
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i-1,j));
    DoneXright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXright )
  {
   Uinner = *Solution(i+1,j) + *JumpConditionRHS(0); 
   DoneXright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 // left side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
 {
  Output += *Solution(i-1,j) *Dx_ell/dx2; 
  OutputCoefficientRHS -= Dx_ell/dx2;
  DoneXleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i-1,j)) );
  
  double GhostCoefficient = Dx_ell/dy2;
  double UinnerCoefficient = 0.0;
  
  // get ghost point u_{i-1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i+2,j) )  )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i+2,j) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i+1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));   
   DoneXleft = true;
  }
  // linear
  if( !DoneXleft  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i+1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXleft = true;
   }
  }				  
  // constant
  if( !DoneXleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)-Theta*dx , *Y(j) );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)-Theta*dx,*Y(j) );
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = *InteriorDiffusivity(i,j);
   Douter = *ExteriorDiffusivity(i-1,j);
  }
  else
  {
   Dinner = *ExteriorDiffusivity(i,j);
   Douter = *InteriorDiffusivity(i-1,j);
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)-Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
      CompareRegions( *Phi(i-1,j),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = -(2.0-Theta);
   double UyOuter = 0.0;
   double VxOuter = -(1.0-Theta);
   double VyOuter = -1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);
   
   double UxInner = (1.0+Theta);
   double UyInner = 0.0;
   double VxInner = Theta;
   double VyInner = 1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i-1,j) ) )
   {
    double temp_u = *Solution(i-1,j-2)*Theta + *Solution(i-2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   

   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i+1,j+2),*Phi(i,j)) )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i+1,j+2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0
							  -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }

   DoneXleft = true; 
  }  

  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-1,j),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i+1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = -(2.0-Theta);
    double UyOuter = 0.0;
    double VxOuter = -(1.0-Theta);
    double VyOuter = 1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = (1.0+Theta);
    double UyInner = 0.0;
    double VxInner = Theta;
    double VyInner = -1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

	*JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j+2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i-1,j) ) )
   {
    double temp_u = *Solution(i-1,j+2)*Theta + *Solution(i-2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   
						   
   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i,j-2),*Phi(i,j) ) && 
       CompareRegions( *Phi(i+1,j-2),*Phi(i,j) ) )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i+1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
							 -temp_u*0.5 )*Dinner*BetaInner; 
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }
						 
    DoneXleft = true; 
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i+2,j), *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i-1,j), *Phi(i-2,j) ) && 
	   CompareRegions( *Phi(i-2,j), *Phi(i-3,j) ) )
   {
	double AlphaOuter = -GDP.NormalX;
	double AlphaInner = GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i-2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i-3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i+1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i+2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXleft = true;	
   }
  
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1 )
	{
     s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
    }
*/

    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	
	
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                     *Solution(i-2,j)*Douter/(2.0-Theta) + *Solution(i+1,j)*Dinner/(1.0+Theta);
    DoneXleft = true; 
   }
  }  
  
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i-1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i-2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i-3,j));
    DoneXleft = true;
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i+1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i+2,j));	  
    DoneXleft = true; 
   }
  }   
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i-1,j))
	                     - (1-Theta)*(*Solution(i-2,j));	  
    DoneXleft = true; 
   }
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i+1,j));
    DoneXleft = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXleft )
  {
   Uinner = *Solution(i-1,j) + *JumpConditionRHS(0); 
   DoneXleft = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // do the y-derivative
 // right side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) )  )
 {
  Output += *Solution(i,j+1) *Dy_r/dy2; 
  OutputCoefficientRHS -= Dy_r/dy2;
  DoneYright = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j+1)) );

  double GhostCoefficient = Dy_r/dy2;
  double UinnerCoefficient = 0.0;
  // get ghost phone u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i,j-2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j-2)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j-1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneYright = true;
  }				  
  // linear
  if( !DoneYright  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j-1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYright = true;
   }
  }				  
  // constant
  if( !DoneYright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)+Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i) , *Y(j)+Theta*dy );
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = *InteriorDiffusivity(i,j);
   Douter = *ExteriorDiffusivity(i,j+1);
  }
  else
  {
   Dinner = *ExteriorDiffusivity(i,j);
   Douter = *InteriorDiffusivity(i,j+1);
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;  
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)+Theta*dy);
  
  if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
      CompareRegions( *Phi(i,j+1),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = 2.0-Theta;
   double VxOuter = 1.0;
   double VyOuter = 1.0-Theta;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = -(1.0+Theta);
   double VxInner = -1.0;
   double VyInner = -Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i,j+1) ) )
   {
    double temp_u = *Solution(i+2,j+1)*Theta + *Solution(i+2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i-2,j) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j-1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }

   DoneYright = true; 
  }  

  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+1),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j-1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = 2.0-Theta;
    double VxOuter = -1.0;
    double VyOuter = 1.0-Theta;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = -(1.0+Theta);
    double VxInner = 1.0;
    double VyInner = -Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i,j+1) ) )
   {
    double temp_u = *Solution(i-2,j+1)*Theta + *Solution(i-2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i+2,j) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i+2,j-1) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j-1)*Theta;
	
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 
						     -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }
						 
    DoneYright = true; 
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j-2), *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j+1), *Phi(i,j+2) ) && 
	   CompareRegions( *Phi(i,j+2), *Phi(i,j+3) ) )
   {
	double AlphaOuter = GDP.NormalY;
	double AlphaInner = -GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j+2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j+3)*(2.0-Theta)/(3.0-Theta));
	*JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j-1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j-2)*(1.0+Theta)/(2.0+Theta));
												
    DoneYright = true;									 
   }
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
     s = 1;
	 if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                       *Solution(i,j+2)*Douter/(2.0-Theta) + *Solution(i,j-1)*Dinner/(1.0+Theta);
    DoneYright = true; 
   }  
  }
  
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j+1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j+2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j+3));
    DoneYright = true;
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j-1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j-2));	  
    DoneYright = true; 
   }
  }   
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j+1))
	                     - (1-Theta)*(*Solution(i,j+2));	  
    DoneYright = true; 
   }
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j-1));
    DoneYright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYright )
  {
   Uinner = *Solution(i,j+1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // left side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
 {
  Output += *Solution(i,j-1) *Dy_ell/dy2; 
  OutputCoefficientRHS -= Dy_ell/dy2;
  DoneYleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j-1)) );

  double GhostCoefficient = Dy_ell/dy2;
  double UinnerCoefficient = 0.0;

  // get ghost phone u_{i-1}
  // quadratic
  if( !DoneYleft && CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) 
                 && CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j+2) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j+1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));     
   DoneYleft = true;
  }				  
  // linear
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j+1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYleft = true;
   }
  }				  
  // constant
  if( !DoneYleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)-Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i),*Y(j)-Theta*dy);
  
  double Dinner, Douter;
  if( *Phi(i,j) <= _EPS )
  {
   Dinner = *InteriorDiffusivity(i,j);
   Douter = *ExteriorDiffusivity(i,j-1);
  }
  else
  {
   Dinner = *ExteriorDiffusivity(i,j);
   Douter = *InteriorDiffusivity(i,j-1);
  }  
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;   
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)-Theta*dy);
  
  if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
      CompareRegions( *Phi(i,j-1),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = -(2.0-Theta);
   double VxOuter = -1.0;
   double VyOuter = -(1.0-Theta);
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = 1.0+Theta;
   double VxInner = 1.0;
   double VyInner = Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i,j-1) ) )
   {
    double temp_u = *Solution(i-2,j-1)*Theta + *Solution(i-2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i+2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i+2,j+1),*Phi(i,j)) )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j+1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						
   DoneYleft = true; 
  }  

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-1),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j+1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = -(2.0-Theta);
    double VxOuter = 1.0;
    double VyOuter = -(1.0-Theta);
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = 1.0+Theta;
    double VxInner = -1.0;
    double VyInner = Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i,j-1) ) )
   {
    double temp_u = *Solution(i+2,j-1)*Theta + *Solution(i+2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i-2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i-2,j+1),*Phi(i,j)) )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j+1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {   
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }	
	
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						 
    DoneYleft = true; 
   }   
  }  
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j+2), *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j+1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j-1), *Phi(i,j-2) ) && 
	   CompareRegions( *Phi(i,j-2), *Phi(i,j-3) ) )
   {
	double AlphaOuter = -GDP.NormalY;
	double AlphaInner = GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j-2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j-3)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j+1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j+2)*(1.0+Theta)/(2.0+Theta));
	
    DoneYleft = true;									 
   }
  
  }  
  
  if( !DoneYleft )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
 	 s = 1;
     if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) =Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                     *Solution(i,j-2)*Douter/(2.0-Theta) + *Solution(i,j+1)*Dinner/(1.0+Theta);
    DoneYleft = true; 
   }  
  } 
 

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j-1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j-2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j-3));
    DoneYleft = true;
   }   
  }
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j+1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j+2));	  
    DoneYleft = true; 
   }
  }   
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j-1))
	                     - (1-Theta)*(*Solution(i,j-2));	  
    DoneYleft = true; 
   }
  }
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j+1));
    DoneYleft = true;
   }
  }

  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYleft )
  {
   Uinner = *Solution(i,j-1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 if( DoneXright && DoneXleft )
 { DoneX = true; }
 if( DoneYright && DoneYleft )
 { DoneY = true; }
 
 // add a non-diffusion case here
 if( !DoneX && !DoneY ) 
 {  
  Output += ( *Solution(i-1,j) * Dx_ell + *Solution(i+1,j) *Dx_r )/dx2;
  Output += ( *Solution(i,j-1) * Dy_ell + *Solution(i,j+1) *Dy_r )/dy2;
  OutputCoefficientRHS -= ( (Dx_ell+Dx_r)/dx2 + (Dy_ell+Dy_r)/dy2 );         
 }
 
 // source 
 OutputCoefficientRHS += *SourceFunctionU(i,j);
 Output += *SourceFunction(i,j);
 Output /= (OutputCoefficientLHS-OutputCoefficientRHS);
 
 return Output; 
}   

double gfmImplicitUpdateContinuousD( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   double(*Diffusivity)(double,double),
   Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy )
{
 extern double _EPS;

 double Uij = *Solution(i,j);
 double dt = 1;
 double dx2 = square(dx);
 double dy2 = square(dy);
 
 double Dx_ell, Dx_r, Dy_ell, Dy_r;
 
 // Compute the centered diffusivities. For now, use constant extrapolations 
 // for the diffusivities. 
 
 
 Dx_r   = Diffusivity(*X(i)+0.5*dx,*Y(j));
 Dx_ell = Diffusivity(*X(i)-0.5*dx,*Y(j));
 Dy_r   = Diffusivity(*X(i),*Y(j)+0.5*dy);
 Dy_ell = Diffusivity(*X(i),*Y(j)-0.5*dy);
 
 double OutputCoefficientLHS = 1.0/dt; 
 double OutputCoefficientRHS = 0.0;
 double Output = Uij/dt;

 bool DoneX = false;
 bool DoneXleft  = false;
 bool DoneXright = false;
 
 bool DoneY = false;
 bool DoneYleft  = false;
 bool DoneYright = false; 
 
 // do the x-derivative
 // right side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
 {
  Output += *Solution(i+1,j) *Dx_r/dx2; 
  OutputCoefficientRHS -= Dx_r/dx2;
  DoneXright = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i+1,j)) );
  
  double GhostCoefficient = Dx_r/dx2;
  double UinnerCoefficient = 0.0;
  // get ghost point u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i-2,j) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i-2,j)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i-1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneXright = true;
  }				  
  // linear
  if( !DoneXright  )
  { 
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i-1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXright = true;
   }
  }				  
  // constant
  if( !DoneXright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)+Theta*dx , *Y(j) );
  
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)+Theta*dx , *Y(j) ); 
  
  double Dinner, Douter;
  Dinner = Diffusivity( *X(i)+Theta*dx, *Y(j) );
  Douter = Dinner;
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0; 
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)+Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
      CompareRegions( *Phi(i+1,j),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 2.0-Theta;
   double UyOuter = 0.0;
   double VxOuter = 1.0-Theta;
   double VyOuter = 1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = -(1.0+Theta);
   double UyInner = 0.0;
   double VxInner = -Theta;
   double VyInner = -1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j+2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i+1,j) ) )
   {
    double temp_u = *Solution(i+1,j+2)*Theta + *Solution(i+2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i,j-2) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i-1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2+Theta)/(1+Theta)
												+*Solution(i-2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						
   DoneXright = true; 
  }

  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+1,j),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i-1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 2.0-Theta;
    double UyOuter = 0.0;
    double VxOuter = 1.0-Theta;
    double VyOuter = -1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = -(1.0+Theta);
    double UyInner = 0.0;
    double VxInner = -Theta;
    double VyInner = 1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j-2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i+1,j) ) )
   {
    double temp_u = *Solution(i+1,j-2)*Theta + *Solution(i+2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i-1,j+2),*Phi(i,j)) )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i-1,j+2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0 
							 -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }
   
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3.0+2.0*Theta)/( (1.0+Theta)*(2.0+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2.0+Theta)/(1.0+Theta)
												+*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						 
    DoneXright = true; 
   }   
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i-2,j), *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i+1,j), *Phi(i+2,j) ) && 
	   CompareRegions( *Phi(i+2,j), *Phi(i+3,j) ) )
   {
	double AlphaOuter = GDP.NormalX;
	double AlphaInner = -GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i+2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i+3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i-1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXright = true;	
   }
  
  }
  
  if( !DoneXright )
  {  
   if( CompareRegions( *Phi(i,j)   , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
	 s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
	}
*/ 
    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	

    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                       *Solution(i+2,j)*Douter/(2.0-Theta) + *Solution(i-1,j)*Dinner/(1.0+Theta);
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i+1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i+2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i+3,j));
    DoneXright = true;
   }   
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i-1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i-2,j));	  
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i+1,j))
	                     - (1-Theta)*(*Solution(i+2,j));	  
    DoneXright = true; 
   }
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i-1,j));
    DoneXright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXright )
  {
   Uinner = *Solution(i+1,j) + *JumpConditionRHS(0); 
   DoneXright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 // left side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
 {
  Output += *Solution(i-1,j) *Dx_ell/dx2; 
  OutputCoefficientRHS -= Dx_ell/dx2;
  DoneXleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i-1,j)) );
  
  double GhostCoefficient = Dx_ell/dy2;
  double UinnerCoefficient = 0.0;
  
  // get ghost point u_{i-1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i+2,j) )  )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i+2,j) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i+1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));   
   DoneXleft = true;
  }
  // linear
  if( !DoneXleft  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i+1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXleft = true;
   }
  }				  
  // constant
  if( !DoneXleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)-Theta*dx , *Y(j) );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)-Theta*dx,*Y(j) );
  
  double Dinner, Douter;
  Dinner = Diffusivity( *X(i)-Theta*dx, *Y(j) );
  Douter = Dinner;
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)-Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
      CompareRegions( *Phi(i-1,j),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = -(2.0-Theta);
   double UyOuter = 0.0;
   double VxOuter = -(1.0-Theta);
   double VyOuter = -1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);
   
   double UxInner = (1.0+Theta);
   double UyInner = 0.0;
   double VxInner = Theta;
   double VyInner = 1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i-1,j) ) )
   {
    double temp_u = *Solution(i-1,j-2)*Theta + *Solution(i-2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   

   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i+1,j+2),*Phi(i,j)) )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i+1,j+2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0
							  -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }

   DoneXleft = true; 
  }  

  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-1,j),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i+1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = -(2.0-Theta);
    double UyOuter = 0.0;
    double VxOuter = -(1.0-Theta);
    double VyOuter = 1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = (1.0+Theta);
    double UyInner = 0.0;
    double VxInner = Theta;
    double VyInner = -1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

	*JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j+2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i-1,j) ) )
   {
    double temp_u = *Solution(i-1,j+2)*Theta + *Solution(i-2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   
						   
   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i,j-2),*Phi(i,j) ) && 
       CompareRegions( *Phi(i+1,j-2),*Phi(i,j) ) )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i+1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
							 -temp_u*0.5 )*Dinner*BetaInner; 
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }
						 
    DoneXleft = true; 
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i+2,j), *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i-1,j), *Phi(i-2,j) ) && 
	   CompareRegions( *Phi(i-2,j), *Phi(i-3,j) ) )
   {
	double AlphaOuter = -GDP.NormalX;
	double AlphaInner = GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i-2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i-3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i+1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i+2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXleft = true;	
   }
  
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1 )
	{
     s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
    }
*/

    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	
	
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                     *Solution(i-2,j)*Douter/(2.0-Theta) + *Solution(i+1,j)*Dinner/(1.0+Theta);
    DoneXleft = true; 
   }
  }  
  
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i-1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i-2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i-3,j));
    DoneXleft = true;
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i+1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i+2,j));	  
    DoneXleft = true; 
   }
  }   
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i-1,j))
	                     - (1-Theta)*(*Solution(i-2,j));	  
    DoneXleft = true; 
   }
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i+1,j));
    DoneXleft = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXleft )
  {
   Uinner = *Solution(i-1,j) + *JumpConditionRHS(0); 
   DoneXleft = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // do the y-derivative
 // right side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) )  )
 {
  Output += *Solution(i,j+1) *Dy_r/dy2; 
  OutputCoefficientRHS -= Dy_r/dy2;
  DoneYright = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j+1)) );

  double GhostCoefficient = Dy_r/dy2;
  double UinnerCoefficient = 0.0;
  // get ghost phone u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i,j-2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j-2)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j-1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneYright = true;
  }				  
  // linear
  if( !DoneYright  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j-1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYright = true;
   }
  }				  
  // constant
  if( !DoneYright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)+Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i) , *Y(j)+Theta*dy );
  
  double Dinner, Douter;
  Dinner = Diffusivity( *X(i),*Y(j)+Theta*dy );
  Douter = Dinner;
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;  
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)+Theta*dy);
  
  if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
      CompareRegions( *Phi(i,j+1),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = 2.0-Theta;
   double VxOuter = 1.0;
   double VyOuter = 1.0-Theta;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = -(1.0+Theta);
   double VxInner = -1.0;
   double VyInner = -Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i,j+1) ) )
   {
    double temp_u = *Solution(i+2,j+1)*Theta + *Solution(i+2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i-2,j) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j-1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }

   DoneYright = true; 
  }  

  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+1),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j-1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = 2.0-Theta;
    double VxOuter = -1.0;
    double VyOuter = 1.0-Theta;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = -(1.0+Theta);
    double VxInner = 1.0;
    double VyInner = -Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i,j+1) ) )
   {
    double temp_u = *Solution(i-2,j+1)*Theta + *Solution(i-2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i+2,j) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i+2,j-1) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j-1)*Theta;
	
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 
						     -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }
						 
    DoneYright = true; 
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j-2), *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j+1), *Phi(i,j+2) ) && 
	   CompareRegions( *Phi(i,j+2), *Phi(i,j+3) ) )
   {
	double AlphaOuter = GDP.NormalY;
	double AlphaInner = -GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j+2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j+3)*(2.0-Theta)/(3.0-Theta));
	*JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j-1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j-2)*(1.0+Theta)/(2.0+Theta));
												
    DoneYright = true;									 
   }
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
     s = 1;
	 if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                       *Solution(i,j+2)*Douter/(2.0-Theta) + *Solution(i,j-1)*Dinner/(1.0+Theta);
    DoneYright = true; 
   }  
  }
  
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j+1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j+2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j+3));
    DoneYright = true;
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j-1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j-2));	  
    DoneYright = true; 
   }
  }   
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j+1))
	                     - (1-Theta)*(*Solution(i,j+2));	  
    DoneYright = true; 
   }
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j-1));
    DoneYright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYright )
  {
   Uinner = *Solution(i,j+1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // left side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
 {
  Output += *Solution(i,j-1) *Dy_ell/dy2; 
  OutputCoefficientRHS -= Dy_ell/dy2;
  DoneYleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j-1)) );

  double GhostCoefficient = Dy_ell/dy2;
  double UinnerCoefficient = 0.0;

  // get ghost phone u_{i-1}
  // quadratic
  if( !DoneYleft && CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) 
                 && CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j+2) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j+1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));     
   DoneYleft = true;
  }				  
  // linear
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j+1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYleft = true;
   }
  }				  
  // constant
  if( !DoneYleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)-Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i),*Y(j)-Theta*dy);
  
  double Dinner, Douter;
  Dinner = Diffusivity( *X(i),*Y(j)-Theta*dy );
  Douter = Dinner;
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;   
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)-Theta*dy);
  
  if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
      CompareRegions( *Phi(i,j-1),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = -(2.0-Theta);
   double VxOuter = -1.0;
   double VyOuter = -(1.0-Theta);
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = 1.0+Theta;
   double VxInner = 1.0;
   double VyInner = Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i,j-1) ) )
   {
    double temp_u = *Solution(i-2,j-1)*Theta + *Solution(i-2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i+2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i+2,j+1),*Phi(i,j)) )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j+1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						
   DoneYleft = true; 
  }  

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-1),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j+1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = -(2.0-Theta);
    double VxOuter = 1.0;
    double VyOuter = -(1.0-Theta);
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = 1.0+Theta;
    double VxInner = -1.0;
    double VyInner = Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i,j-1) ) )
   {
    double temp_u = *Solution(i+2,j-1)*Theta + *Solution(i+2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i-2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i-2,j+1),*Phi(i,j)) )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j+1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {   
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }	
	
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						 
    DoneYleft = true; 
   }   
  }  
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j+2), *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j+1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j-1), *Phi(i,j-2) ) && 
	   CompareRegions( *Phi(i,j-2), *Phi(i,j-3) ) )
   {
	double AlphaOuter = -GDP.NormalY;
	double AlphaInner = GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j-2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j-3)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j+1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j+2)*(1.0+Theta)/(2.0+Theta));
	
    DoneYleft = true;									 
   }
  
  }  
  
  if( !DoneYleft )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
 	 s = 1;
     if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) =Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                     *Solution(i,j-2)*Douter/(2.0-Theta) + *Solution(i,j+1)*Dinner/(1.0+Theta);
    DoneYleft = true; 
   }  
  } 
 

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j-1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j-2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j-3));
    DoneYleft = true;
   }   
  }
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j+1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j+2));	  
    DoneYleft = true; 
   }
  }   
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j-1))
	                     - (1-Theta)*(*Solution(i,j-2));	  
    DoneYleft = true; 
   }
  }
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j+1));
    DoneYleft = true;
   }
  }

  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYleft )
  {
   Uinner = *Solution(i,j-1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 if( DoneXright && DoneXleft )
 { DoneX = true; }
 if( DoneYright && DoneYleft )
 { DoneY = true; }
 
 // add a non-diffusion case here
 if( !DoneX && !DoneY ) 
 {  
  Output += ( *Solution(i-1,j) * Dx_ell + *Solution(i+1,j) *Dx_r )/dx2;
  Output += ( *Solution(i,j-1) * Dy_ell + *Solution(i,j+1) *Dy_r )/dy2;
  OutputCoefficientRHS -= ( (Dx_ell+Dx_r)/dx2 + (Dy_ell+Dy_r)/dy2 );         
 }
 
 // source 
 OutputCoefficientRHS += *SourceFunctionU(i,j);
 Output += *SourceFunction(i,j);
 Output /= (OutputCoefficientLHS-OutputCoefficientRHS);
 
 return Output; 
}   

double gfmImplicitUpdateContinuousD_MatrixForm( Matrix& X,Matrix& Y,Matrix& Phi, Matrix& Solution, 
   Matrix& Diffusivity,
   Matrix& SourceFunction, 
   Matrix& SourceFunctionU, 
   double (*JumpCondition)(double,double),
   double (*NormalDerivativeJumpCondition)(double,double),
   int i, int j, double dx, double dy )
{
 extern double _EPS;

 double Uij = *Solution(i,j);
 double dt = 1;
 double dx2 = square(dx);
 double dy2 = square(dy);
 
 double Dx_ell, Dx_r, Dy_ell, Dy_r;
 
 // Compute the centered diffusivities. For now, use constant extrapolations 
 // for the diffusivities. 
 
 
 Dx_r   = 0.5*( *Diffusivity(i,j) + *Diffusivity(i+1,j) );
 Dx_ell = 0.5*( *Diffusivity(i,j) + *Diffusivity(i-1,j) );
 Dy_r   = 0.5*( *Diffusivity(i,j) + *Diffusivity(i,j+1) );
 Dy_ell = 0.5*( *Diffusivity(i,j) + *Diffusivity(i,j-1) );
 
 double OutputCoefficientLHS = 1.0/dt; 
 double OutputCoefficientRHS = 0.0;
 double Output = Uij/dt;

 bool DoneX = false;
 bool DoneXleft  = false;
 bool DoneXright = false;
 
 bool DoneY = false;
 bool DoneYleft  = false;
 bool DoneYright = false; 
 
 // do the x-derivative
 // right side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
 {
  Output += *Solution(i+1,j) *Dx_r/dx2; 
  OutputCoefficientRHS -= Dx_r/dx2;
  DoneXright = true;
 }
 else
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i+1,j)) );
  
  double GhostCoefficient = Dx_r/dx2;
  double UinnerCoefficient = 0.0;
  // get ghost point u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i-2,j) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i-2,j)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i-1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneXright = true;
  }				  
  // linear
  if( !DoneXright  )
  { 
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i-1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXright = true;
   }
  }				  
  // constant
  if( !DoneXright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)+Theta*dx , *Y(j) );
  
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)+Theta*dx , *Y(j) ); 
  
  double Dinner, Douter;
  Dinner = *Diffusivity(i,j)*(1.0-Theta) + *Diffusivity(i+1,j)*Theta;
  Douter = Dinner;
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0; 
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)+Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
      CompareRegions( *Phi(i+1,j),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 2.0-Theta;
   double UyOuter = 0.0;
   double VxOuter = 1.0-Theta;
   double VyOuter = 1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = -(1.0+Theta);
   double UyInner = 0.0;
   double VxInner = -Theta;
   double VyInner = -1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j+2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i+1,j) ) )
   {
    double temp_u = *Solution(i+1,j+2)*Theta + *Solution(i+2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i,j-2) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i-1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2+Theta)/(1+Theta)
												+*Solution(i-2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						
   DoneXright = true; 
  }

  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j),*Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+1,j),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i-1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 2.0-Theta;
    double UyOuter = 0.0;
    double VxOuter = 1.0-Theta;
    double VyOuter = -1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = -(1.0+Theta);
    double UyInner = 0.0;
    double VxInner = -Theta;
    double VyInner = 1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i+1,j-2) , *Phi(i+1,j) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i+1,j) ) )
   {
    double temp_u = *Solution(i+1,j-2)*Theta + *Solution(i+2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   

   if( CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i+2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i+3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i+2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i-1,j+2),*Phi(i,j)) )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i-1,j+2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0 
							 -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }
   
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3.0+2.0*Theta)/( (1.0+Theta)*(2.0+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i-1,j)*(2.0+Theta)/(1.0+Theta)
												+*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*AlphaInner;
   }
						 
    DoneXright = true; 
   }   
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i-2,j), *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i+1,j), *Phi(i+2,j) ) && 
	   CompareRegions( *Phi(i+2,j), *Phi(i+3,j) ) )
   {
	double AlphaOuter = GDP.NormalX;
	double AlphaInner = -GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i+2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i+3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i-1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i-2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXright = true;	
   }
  
  }
  
  if( !DoneXright )
  {  
   if( CompareRegions( *Phi(i,j)   , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
	 s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
	}
*/ 
    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	

    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                       *Solution(i+2,j)*Douter/(2.0-Theta) + *Solution(i-1,j)*Dinner/(1.0+Theta);
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) &&
       CompareRegions( *Phi(i+2,j) , *Phi(i+3,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i+1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i+2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i+3,j));
    DoneXright = true;
   }   
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i-1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i-2,j));	  
    DoneXright = true; 
   }
  }   
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i+1,j))
	                     - (1-Theta)*(*Solution(i+2,j));	  
    DoneXright = true; 
   }
  }
  
  if( !DoneXright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i-1,j));
    DoneXright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXright )
  {
   Uinner = *Solution(i+1,j) + *JumpConditionRHS(0); 
   DoneXright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 // left side of the x-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i-1,j) ) )
 {
  Output += *Solution(i-1,j) *Dx_ell/dx2; 
  OutputCoefficientRHS -= Dx_ell/dx2;
  DoneXleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i-1,j)) );
  
  double GhostCoefficient = Dx_ell/dy2;
  double UinnerCoefficient = 0.0;
  
  // get ghost point u_{i-1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i+2,j) )  )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i+2,j) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i+1,j) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));   
   DoneXleft = true;
  }
  // linear
  if( !DoneXleft  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i+1,j);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneXleft = true;
   }
  }				  
  // constant
  if( !DoneXleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneXleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i)-Theta*dx , *Y(j) );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i)-Theta*dx,*Y(j) );
  
  double Dinner, Douter;
  Dinner = *Diffusivity(i,j)*(1.0-Theta) + *Diffusivity(i-1,j)*Theta;
  Douter = Dinner;
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneXleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i)-Theta*dx,*Y(j));
  
  if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
      CompareRegions( *Phi(i-1,j),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = -(2.0-Theta);
   double UyOuter = 0.0;
   double VxOuter = -(1.0-Theta);
   double VyOuter = -1.0;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);
   
   double UxInner = (1.0+Theta);
   double UyInner = 0.0;
   double VxInner = Theta;
   double VyInner = 1.0;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j-2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i-1,j) ) )
   {
    double temp_u = *Solution(i-1,j-2)*Theta + *Solution(i-2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   

   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i,j+2),*Phi(i,j)) && 
       CompareRegions(*Phi(i+1,j+2),*Phi(i,j)) )
   {
    double temp_u = *Solution(i,j+2)*(1-Theta) + *Solution(i+1,j+2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j+1)*2.0
							  -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }

   DoneXleft = true; 
  }  

  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j),*Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-1,j),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i+1,j) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i,j-1)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = -(2.0-Theta);
    double UyOuter = 0.0;
    double VxOuter = -(1.0-Theta);
    double VyOuter = 1.0;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = (1.0+Theta);
    double UyInner = 0.0;
    double VxInner = Theta;
    double VyInner = -1.0;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

	*JumpConditionRHS(1) =  NormalDerivativeJump*dx;
   if( CompareRegions( *Phi(i-1,j+2) , *Phi(i-1,j) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i-1,j) ) )
   {
    double temp_u = *Solution(i-1,j+2)*Theta + *Solution(i-2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }						   
						   
						   
   if( CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i-2,j)*(3-Theta)/(2-Theta)
											   -*Solution(i-3,j)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i-2,j)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i,j-2),*Phi(i,j) ) && 
       CompareRegions( *Phi(i+1,j-2),*Phi(i,j) ) )
   {
    double temp_u = *Solution(i,j-2)*(1-Theta) + *Solution(i+1,j-2)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*(1.5);
	*JumpConditionRHS(1) -= ( *Solution(i,j-1)*2.0 
							 -temp_u*0.5 )*Dinner*BetaInner; 
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i+1,j)*(2+Theta)/(1+Theta)
												+*Solution(i+2,j)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*AlphaInner;
   }
						 
    DoneXleft = true; 
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i+2,j), *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i-1,j), *Phi(i-2,j) ) && 
	   CompareRegions( *Phi(i-2,j), *Phi(i-3,j) ) )
   {
	double AlphaOuter = -GDP.NormalX;
	double AlphaInner = GDP.NormalX;
   
    *JumpConditionRHS(1) = dx*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i-2,j)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i-3,j)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i+1,j)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i+2,j)*(1.0+Theta)/(2.0+Theta));
	
    DoneXleft = true;	
   }
  
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
/*   
    double s = GDP.NormalX;
	if( fabs(s) < 1e-10 || 1 == 1 )
	{
     s = 1;
	 if( GDP.NormalX <= _EPS )
	 { s = -1; }
    }
*/

    int s = 1;
    if( GDP.NormalX <= _EPS )
    { s *= -1; }	
	
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dx*NormalDerivativeJump*s + // /GDP.NormalX + 
	                     *Solution(i-2,j)*Douter/(2.0-Theta) + *Solution(i+1,j)*Dinner/(1.0+Theta);
    DoneXleft = true; 
   }
  }  
  
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) &&
       CompareRegions( *Phi(i-2,j) , *Phi(i-3,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i-1,j))
	                                - (1-Theta)*(3-Theta)*(*Solution(i-2,j))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i-3,j));
    DoneXleft = true;
   }   
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) && 
       CompareRegions( *Phi(i+1,j) , *Phi(i+2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i+1,j))
						 + 0.5*Theta*(1+Theta)*(*Solution(i+2,j));	  
    DoneXleft = true; 
   }
  }   
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i-1,j) , *Phi(i-2,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i-1,j))
	                     - (1-Theta)*(*Solution(i-2,j));	  
    DoneXleft = true; 
   }
  }
  
  if( !DoneXleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i+1,j) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i+1,j));
    DoneXleft = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneXleft )
  {
   Uinner = *Solution(i-1,j) + *JumpConditionRHS(0); 
   DoneXleft = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // do the y-derivative
 // right side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) )  )
 {
  Output += *Solution(i,j+1) *Dy_r/dy2; 
  OutputCoefficientRHS -= Dy_r/dy2;
  DoneYright = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j+1)) );

  double GhostCoefficient = Dy_r/dy2;
  double UinnerCoefficient = 0.0;
  // get ghost phone u_{i+1}
  // quadratic
  if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) &&
      CompareRegions( *Phi(i,j) , *Phi(i,j-2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j-2)
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j-1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));
   DoneYright = true;
  }				  
  // linear
  if( !DoneYright  )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j-1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYright = true;
   }
  }				  
  // constant
  if( !DoneYright )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYright = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)+Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i) , *Y(j)+Theta*dy );
  
  double Dinner, Douter;
  Dinner = *Diffusivity(i,j)*(1.0-Theta) + *Diffusivity(i,j+1)*Theta;
  Douter = Dinner;
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;  
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYright = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)+Theta*dy);
  
  if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
      CompareRegions( *Phi(i,j+1),*Phi(i+1,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = 2.0-Theta;
   double VxOuter = 1.0;
   double VyOuter = 1.0-Theta;
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = -(1.0+Theta);
   double VxInner = -1.0;
   double VyInner = -Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i+2,j+2) , *Phi(i,j+1) ) )
   {
    double temp_u = *Solution(i+2,j+1)*Theta + *Solution(i+2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i-2,j) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j-1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 
	                          -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }

   DoneYright = true; 
  }  

  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1),*Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+1),*Phi(i-1,j+1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j-1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = 2.0-Theta;
    double VxOuter = -1.0;
    double VyOuter = 1.0-Theta;
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = -(1.0+Theta);
    double VxInner = 1.0;
    double VyInner = -Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 
						   
   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j+1) , *Phi(i,j+1) ) &&
       CompareRegions( *Phi(i-2,j+2) , *Phi(i,j+1) ) )
   {
    double temp_u = *Solution(i-2,j+1)*Theta + *Solution(i-2,j+2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j+1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j+1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   

   if( CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j+2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j+3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j+2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions( *Phi(i+2,j) , *Phi(i,j) ) && 
       CompareRegions( *Phi(i+2,j-1) , *Phi(i,j) ) )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j-1)*Theta;
	
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 
						     -temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j-1)*(2+Theta)/(1+Theta)
												+*Solution(i,j-2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j-1)*Dinner*AlphaInner;
   }
						 
    DoneYright = true; 
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j-2), *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j+1), *Phi(i,j+2) ) && 
	   CompareRegions( *Phi(i,j+2), *Phi(i,j+3) ) )
   {
	double AlphaOuter = GDP.NormalY;
	double AlphaInner = -GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j+2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j+3)*(2.0-Theta)/(3.0-Theta));
	*JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j-1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j-2)*(1.0+Theta)/(2.0+Theta));
												
    DoneYright = true;									 
   }
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j)   , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
     s = 1;
	 if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) = Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                       *Solution(i,j+2)*Douter/(2.0-Theta) + *Solution(i,j-1)*Dinner/(1.0+Theta);
    DoneYright = true; 
   }  
  }
  
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) &&
       CompareRegions( *Phi(i,j+2) , *Phi(i,j+3) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j+1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j+2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j+3));
    DoneYright = true;
   }   
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j-1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j-2));	  
    DoneYright = true; 
   }
  }   
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j+1))
	                     - (1-Theta)*(*Solution(i,j+2));	  
    DoneYright = true; 
   }
  }
  
  if( !DoneYright )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j-1));
    DoneYright = true;
   }
  }
  
  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYright )
  {
   Uinner = *Solution(i,j+1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }
 
 // left side of the y-derivative
 if( CompareRegions( *Phi(i,j) , *Phi(i,j-1) ) )
 {
  Output += *Solution(i,j-1) *Dy_ell/dy2; 
  OutputCoefficientRHS -= Dy_ell/dy2;
  DoneYleft = true;
 }
 else // 2-1-2007
 {
  double Theta = fabs( *Phi(i,j) )/( fabs(*Phi(i,j)) + fabs(*Phi(i,j-1)) );

  double GhostCoefficient = Dy_ell/dy2;
  double UinnerCoefficient = 0.0;

  // get ghost phone u_{i-1}
  // quadratic
  if( !DoneYleft && CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) 
                 && CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
  {  
   Output += GhostCoefficient*( 2.0*(1.0-Theta)/(2.0+Theta)* *Solution(i,j+2) 
                               -3.0*(1.0-Theta)/(1.0+Theta)* *Solution(i,j+1) );
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 6.0/((1.0+Theta)*(2.0+Theta));     
   DoneYleft = true;
  }				  
  // linear
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   { 
    Output -= GhostCoefficient*(1.0-Theta)/(1.0+Theta) * *Solution(i,j+1);
    OutputCoefficientRHS -= GhostCoefficient;   
    UinnerCoefficient = 2.0/(1.0+Theta);
    DoneYleft = true;
   }
  }				  
  // constant
  if( !DoneYleft )
  { 
   OutputCoefficientRHS -= GhostCoefficient;
   UinnerCoefficient = 1.0;
   DoneYleft = true; 
  }
  // set up the conditions to get u_inner and u_outer
  Matrix JumpConditionCoefficientMatrix = zeros(2,2);
  Matrix JumpConditionRHS = zeros(1,2);
  *JumpConditionCoefficientMatrix(0,0) = 1.0; 
  *JumpConditionCoefficientMatrix(0,1) = -1.0; 
  double Uinner; 
  *JumpConditionRHS(0) = JumpCondition( *X(i), *Y(j)-Theta*dy );
  double NormalDerivativeJump = NormalDerivativeJumpCondition( *X(i),*Y(j)-Theta*dy);
  
  double Dinner, Douter;
  Dinner = *Diffusivity(i,j)*(1.0-Theta) + *Diffusivity(i,j-1)*Theta;
  Douter = Dinner;
  
  if( *Phi(i,j) > _EPS )
  {
   *JumpConditionRHS(0) *= -1.0; 
   NormalDerivativeJump *= -1.0;   
  }
  // discretize the normal jump. For now, do it in a primitive way.
  DoneYleft = false;
  
  GeometricDataPacket GDP = AdaptiveGeometricData(X,Y,Phi,*X(i),*Y(j)-Theta*dy);
  
  if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
      CompareRegions( *Phi(i,j-1),*Phi(i-1,j-1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i,j+1) ) &&
	  CompareRegions( *Phi(i,j),*Phi(i+1,j)) &&
	  GDP.NormalX * GDP.NormalY > _EPS )
  {
   double UxOuter = 0.0;
   double UyOuter = -(2.0-Theta);
   double VxOuter = -1.0;
   double VyOuter = -(1.0-Theta);
   
   Matrix NormalSystemOuter(2,2);
   *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
   *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
   *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
   *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
   Matrix NormalSystemOuterRHS(1,2);
   *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
   *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
   Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
   double AlphaOuter = *AlphaBetaOuter(0);
   double BetaOuter = *AlphaBetaOuter(1);

   double UxInner = 0.0;
   double UyInner = 1.0+Theta;
   double VxInner = 1.0;
   double VyInner = Theta;
   
   Matrix NormalSystemInner(2,2);
   *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
   *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
   *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
   *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
   Matrix NormalSystemInnerRHS(1,2);
   *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
   *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
   Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
   double AlphaInner = *AlphaBetaInner(0);
   double BetaInner = *AlphaBetaInner(1);

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i-2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i-2,j-2) , *Phi(i,j-1) ) )
   {
    double temp_u = *Solution(i-2,j-1)*Theta + *Solution(i-2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i-1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i-1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i+2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i+2,j+1),*Phi(i,j)) )
   {
    double temp_u = *Solution(i+2,j)*(1-Theta) + *Solution(i+2,j+1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i+1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i+1,j)*Dinner*BetaInner;
   }	
						
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						
   DoneYleft = true; 
  }  

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1),*Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-1),*Phi(i+1,j-1) ) &&
 	   CompareRegions( *Phi(i,j),*Phi(i,j+1) ) && 
	   CompareRegions( *Phi(i,j),*Phi(i-1,j)) &&
	   GDP.NormalX * GDP.NormalY <= _EPS )
   {
    double UxOuter = 0.0;
    double UyOuter = -(2.0-Theta);
    double VxOuter = 1.0;
    double VyOuter = -(1.0-Theta);
    
    Matrix NormalSystemOuter(2,2);
    *NormalSystemOuter(0,0) = UxOuter*UxOuter + UyOuter*UyOuter;
    *NormalSystemOuter(0,1) = UxOuter*VxOuter + UyOuter*VyOuter;
    *NormalSystemOuter(1,0) = *NormalSystemOuter(0,1);
    *NormalSystemOuter(1,1) = VxOuter*VxOuter + VyOuter*VyOuter;
    Matrix NormalSystemOuterRHS(1,2);
    *NormalSystemOuterRHS(0) = GDP.NormalX*UxOuter + GDP.NormalY*UyOuter;
    *NormalSystemOuterRHS(1) = GDP.NormalX*VxOuter + GDP.NormalY*VyOuter;
    Matrix AlphaBetaOuter = linsolve2by2(NormalSystemOuter,NormalSystemOuterRHS);
    double AlphaOuter = *AlphaBetaOuter(0);
    double BetaOuter = *AlphaBetaOuter(1);
    
    double UxInner = 0.0;
    double UyInner = 1.0+Theta;
    double VxInner = -1.0;
    double VyInner = Theta;
    
    Matrix NormalSystemInner(2,2);
    *NormalSystemInner(0,0) = UxInner*UxInner + UyInner*UyInner;
    *NormalSystemInner(0,1) = UxInner*VxInner + UyInner*VyInner;
    *NormalSystemInner(1,0) = *NormalSystemInner(0,1);
    *NormalSystemInner(1,1) = VxInner*VxInner + VyInner*VyInner;
    Matrix NormalSystemInnerRHS(1,2);
    *NormalSystemInnerRHS(0) = GDP.NormalX*UxInner + GDP.NormalY*UyInner;
    *NormalSystemInnerRHS(1) = GDP.NormalX*VxInner + GDP.NormalY*VyInner;
    Matrix AlphaBetaInner = linsolve2by2(NormalSystemInner,NormalSystemInnerRHS);
    double AlphaInner = *AlphaBetaInner(0);
    double BetaInner = *AlphaBetaInner(1); 

   *JumpConditionRHS(1) =  NormalDerivativeJump*dy;
   if( CompareRegions( *Phi(i+2,j-1) , *Phi(i,j-1) ) &&
       CompareRegions( *Phi(i+2,j-2) , *Phi(i,j-1) ) )
   {
    double temp_u = *Solution(i+2,j-1)*Theta + *Solution(i+2,j-2)*(1-Theta);
	*JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter*(1.5);
	*JumpConditionRHS(1) += ( *Solution(i+1,j-1)*2.0 
	                         -temp_u*0.5 )*Douter*BetaOuter;
   }
   else
   {
    *JumpConditionRHS(1) += *Solution(i+1,j-1)*BetaOuter*Douter;
    *JumpConditionCoefficientMatrix(1,1) += Douter*BetaOuter;
   }
						   
   if( CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    AlphaOuter *= (2-Theta);
    *JumpConditionCoefficientMatrix(1,1) -= ( (square(2-Theta)-square(3-Theta))
											  /( (2-Theta)*(3-Theta) ) )*Douter*AlphaOuter;
    *JumpConditionRHS(1) += Douter*AlphaOuter*( *Solution(i,j-2)*(3-Theta)/(2-Theta)
											   -*Solution(i,j-3)*(2-Theta)/(3-Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,1) += Douter*AlphaOuter;
	*JumpConditionRHS(1) += *Solution(i,j-2)*Douter*AlphaOuter;
   }
   
   if( CompareRegions(*Phi(i-2,j),*Phi(i,j)) && 
       CompareRegions(*Phi(i-2,j+1),*Phi(i,j)) )
   {
    double temp_u = *Solution(i-2,j)*(1-Theta) + *Solution(i-2,j+1)*Theta;
	*JumpConditionCoefficientMatrix(1,0) -= BetaInner*Dinner*1.5;
	*JumpConditionRHS(1) -= ( *Solution(i-1,j)*2.0 - temp_u*0.5 )*BetaInner*Dinner;
   }
   else
   {   
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*BetaInner;
    *JumpConditionRHS(1) -= *Solution(i-1,j)*Dinner*BetaInner;
   }	
	
   if( CompareRegions( *Phi(i,j+1) , *Phi(i,j+2) ) )
   {
    AlphaInner *= (1+Theta);
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner*( (3+2*Theta)/( (1+Theta)*(2+Theta) ) );
	*JumpConditionRHS(1) += Dinner*AlphaInner*( -*Solution(i,j+1)*(2+Theta)/(1+Theta)
												+*Solution(i,j+2)*(1+Theta)/(2+Theta) );
   }
   else
   {
    *JumpConditionCoefficientMatrix(1,0) -= Dinner*AlphaInner;
    *JumpConditionRHS(1) -= *Solution(i,j+1)*Dinner*AlphaInner;
   }
						 
    DoneYleft = true; 
   }   
  }  
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j+2), *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j+1), *Phi(i,j)   ) && 
	   CompareRegions( *Phi(i,j-1), *Phi(i,j-2) ) && 
	   CompareRegions( *Phi(i,j-2), *Phi(i,j-3) ) )
   {
	double AlphaOuter = -GDP.NormalY;
	double AlphaInner = GDP.NormalY;
   
    *JumpConditionRHS(1) = dy*NormalDerivativeJump;

    *JumpConditionCoefficientMatrix(1,1) += -AlphaOuter*Douter*( -(5.0-2.0*Theta)/((2.0-Theta)*(3.0-Theta)) );
	*JumpConditionRHS(1) -= -AlphaOuter*Douter*(  *Solution(i,j-2)*(3.0-Theta)/(2.0-Theta) 
												 -*Solution(i,j-3)*(2.0-Theta)/(3.0-Theta));

    *JumpConditionCoefficientMatrix(1,0) += AlphaInner*Dinner*( -(3.0+2.0*Theta)/((1.0+Theta)*(2.0+Theta)) );
	*JumpConditionRHS(1) -= AlphaInner*Dinner*(  *Solution(i,j+1)*(2.0+Theta)/(1.0+Theta) 
												-*Solution(i,j+2)*(1.0+Theta)/(2.0+Theta));
	
    DoneYleft = true;									 
   }
  
  }  
  
  if( !DoneYleft )
  {  
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
/*   
    double s = GDP.NormalY;
	if( fabs(s) < 1e-10 || 1 == 1)
	{
 	 s = 1;
     if( GDP.NormalY <= _EPS )
	 { s = -1; }
	}
*/
    int s = 1;
    if( GDP.NormalY <= _EPS )
    { s *= -1; }	
   
    *JumpConditionCoefficientMatrix(1,0) =Dinner/(1.0+Theta); 
    *JumpConditionCoefficientMatrix(1,1) = Douter/(2.0-Theta);
    *JumpConditionRHS(1) = -dy*NormalDerivativeJump*s + // /GDP.NormalY + 
	                     *Solution(i,j-2)*Douter/(2.0-Theta) + *Solution(i,j+1)*Dinner/(1.0+Theta);
    DoneYleft = true; 
   }  
  } 
 

  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) &&
       CompareRegions( *Phi(i,j-2) , *Phi(i,j-3) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0; 
	*JumpConditionCoefficientMatrix(1,1) = 1;
	*JumpConditionRHS(1) = 0.5*(2-Theta)*(3-Theta)*(*Solution(i,j-1))
	                                - (1-Theta)*(3-Theta)*(*Solution(i,j-2))
						            + 0.5*(1-Theta)*(2-Theta)*(*Solution(i,j-3));
    DoneYleft = true;
   }   
  }
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) && 
       CompareRegions( *Phi(i,j) , *Phi(i,j+2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
    *JumpConditionCoefficientMatrix(1,1) = 0.0;
    *JumpConditionRHS(1) = 0.5*(1+Theta)*(2+Theta)*(*Solution(i,j))
	                     - Theta*(2+Theta)*(*Solution(i,j+1))
						 + 0.5*Theta*(1+Theta)*(*Solution(i,j+2));	  
    DoneYleft = true; 
   }
  }   
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j-1) , *Phi(i,j-2) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 0.0; 
    *JumpConditionCoefficientMatrix(1,1) = 1.0;
    *JumpConditionRHS(1) = (2.0-Theta)*(*Solution(i,j-1))
	                     - (1-Theta)*(*Solution(i,j-2));	  
    DoneYleft = true; 
   }
  }
  
  if( !DoneYleft )
  {
   if( CompareRegions( *Phi(i,j) , *Phi(i,j+1) ) )
   {
    *JumpConditionCoefficientMatrix(1,0) = 1.0; 
	*JumpConditionCoefficientMatrix(1,1) = 0.0;
	*JumpConditionRHS(1) = (1+Theta)*(*Solution(i,j)) 
	                     -Theta*(*Solution(i,j+1));
    DoneYleft = true;
   }
  }

  // if slope is zero on left and right, don't bother solving the system
  if( !DoneYleft )
  {
   Uinner = *Solution(i,j-1) + *JumpConditionRHS(0); 
   DoneYright = true;
  }
  else
  {
   Matrix Temp = linsolve2by2( JumpConditionCoefficientMatrix, JumpConditionRHS ); 
   Uinner = *Temp(0);  
  }
  Output += GhostCoefficient*UinnerCoefficient*Uinner;
 }

 if( DoneXright && DoneXleft )
 { DoneX = true; }
 if( DoneYright && DoneYleft )
 { DoneY = true; }
 
 // add a non-diffusion case here
 if( !DoneX && !DoneY ) 
 {  
  Output += ( *Solution(i-1,j) * Dx_ell + *Solution(i+1,j) *Dx_r )/dx2;
  Output += ( *Solution(i,j-1) * Dy_ell + *Solution(i,j+1) *Dy_r )/dy2;
  OutputCoefficientRHS -= ( (Dx_ell+Dx_r)/dx2 + (Dy_ell+Dy_r)/dy2 );         
 }
 
 // source 
 OutputCoefficientRHS += *SourceFunctionU(i,j);
 Output += *SourceFunction(i,j);
 Output /= (OutputCoefficientLHS-OutputCoefficientRHS);
 
 return Output; 
}   

Matrix GhostFluidMethod_Generic(Matrix& X, Matrix& Y, Matrix& Phi, 
   double (*Diffusivity)(double,double), 
   Matrix& SourceFunction, Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance,
   double (*gfmUpdateFunction)(Matrix&,Matrix&,Matrix&,Matrix&,
                               double(*)(double,double),
							   Matrix&,Matrix&,
							   double(*)(double,double),
							   double(*)(double,double),
							   int,int,double,double) )
{
 extern double dx;
 extern double dy;

 int i,j;

 Matrix Output = InitialGuess; 
 
 int Iteration = 0;
 double Error = 2*Tolerance;

 double SelectionRatio = 0.25;
 double SelectionCriterion = Tolerance; 

 SolverPoint* pHeadSolverPoint = NULL;
 SolverPoint* pCurrentSolverPoint = pHeadSolverPoint;

 int MaxSolverPoints = ( X.TellCols() * Y.TellCols() )/4; 
 int NumberOfSolverPoints = 0;
 
 bool GiveUp = false;
 int GiveUpThreshold = (int) floor( (0.015*X.TellCols())*(0.015*Y.TellCols()) );
 
 int SweepDirectionI,SweepDirectionJ;
 int StartI,EndI;
 int StartJ,EndJ;
 
 int k=0;
 while( Iteration < MaxIterations && Error > Tolerance )
 {
  // Set the sweep directions
  if( k % 4 == 0 )
  { 
   SweepDirectionI = 1;
   StartI = 1;
   EndI = InitialGuess.TellRows()-1;
   SweepDirectionJ = 1;
   StartJ = 1;
   EndJ = InitialGuess.TellCols()-1;
  }
  if( k % 4 == 1 )
  { 
   SweepDirectionI = -1;
   EndI = 1;
   StartI = InitialGuess.TellRows()-2;
   SweepDirectionJ = 0;
   StartJ = 1;
   EndJ = InitialGuess.TellCols()-1;
  }
  if( k % 4 == 2 )
  { 
   SweepDirectionI = 1;
   StartI = 1;
   EndI = InitialGuess.TellRows()-1;
   SweepDirectionJ = -1;
   EndJ = 0;
   StartJ = InitialGuess.TellCols()-2;
  }
  if( k % 4 == 3 )
  { 
   SweepDirectionI = -1;
   EndI = 0;
   StartI = InitialGuess.TellRows()-2;
   SweepDirectionJ = -1;
   EndJ = 0;
   StartJ = InitialGuess.TellCols()-2;
  }
  
  // update the boundary points
  
  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   j=Y.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   i=X.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }				
  
  // sweep and note the maximum
  
  Error = 0.0;
  i = StartI;
  while( i != EndI )
  {
   j = StartJ;
   while( j != EndJ )
   {
    double NewValue = gfmUpdateFunction(X,Y,Phi,Output, 
	 Diffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	double change = fabs( NewValue - *Output(i,j) );
	if( change > Error )
	{ Error = change; }
	*Output(i,j) = NewValue;
	j += SweepDirectionJ;
   }
   i += SweepDirectionI;
  }
  Iteration++;
  
  // create the selection criterion 
  
  SelectionCriterion = SelectionRatio*Error;
  pCurrentSolverPoint = pHeadSolverPoint;
  NumberOfSolverPoints = 0;
  
  // sweep and create the list 
  
  i = StartI;
  while( i != EndI )
  {
   j = StartJ;
   while( j != EndJ )
   {
    double NewValue = gfmUpdateFunction(X,Y,Phi,Output, 
	 Diffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	double change = fabs( NewValue - *Output(i,j) );
	*Output(i,j) = NewValue;
	
	if( change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints )
	{
     SolverPoint* pNewSolverPoint;
	 pNewSolverPoint = new SolverPoint; 
	 pNewSolverPoint->i = i;
	 pNewSolverPoint->j = j;
	 NumberOfSolverPoints++;
	 if( pCurrentSolverPoint )
	 { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	 else
	 { pHeadSolverPoint = pNewSolverPoint; }
	 pCurrentSolverPoint = pNewSolverPoint; 
	}
	j += SweepDirectionJ;
   }
   i += SweepDirectionI;
  }
  Iteration++;

  // sweep over the list 

  int ListIteration = 0;
  double TempError = 2.0*SelectionCriterion; 
  int MaxInternalIterations = 2;
  while( ListIteration < MaxInternalIterations && 
         TempError > 0.99*SelectionCriterion && 
		 TempError < 1 )
  {
   TempError = 0.0;
   pCurrentSolverPoint = pHeadSolverPoint;
   while( pCurrentSolverPoint )
   {
    i = pCurrentSolverPoint->i;
	j = pCurrentSolverPoint->j;
    double NewValue = gfmUpdateFunction(X,Y,Phi,Output, 
	 Diffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	double change = fabs( NewValue - *Output(i,j) );
	*Output(i,j) = NewValue;   
	if( change > TempError )
	{ TempError = change; }
   
    pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint;
   }
   ListIteration++;
  }
  
  // delete the list

  pCurrentSolverPoint = pHeadSolverPoint;  
  while( pHeadSolverPoint )
  {
   pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
   delete pHeadSolverPoint;
   pHeadSolverPoint = pCurrentSolverPoint;
  }

  if( Iteration % 1000 == 0 )
  { cout << Iteration << " : " << Error << endl; }  

  k++;
 }
 cout << "summary:: iterations: " << Iteration << endl
      << "          error     : " << Error << endl << endl;
 if( GiveUp )
 {
  cout << "Gave up because adaptivity was being focused on less than 0.0225% of nodes!" << endl
       << "(" << NumberOfSolverPoints << " nodes)" << endl << endl; 
 } 
 return Output;
} 

Matrix GhostFluidMethod_Generic_MatrixForm(Matrix& X, Matrix& Y, Matrix& Phi, 
   Matrix& Diffusivity, 
   Matrix& SourceFunction, Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance,
   double (*gfmUpdateFunction)(Matrix&,Matrix&,Matrix&,Matrix&,
                               Matrix&,
							   Matrix&,Matrix&,
							   double(*)(double,double),
							   double(*)(double,double),
							   int,int,double,double) )
{
 extern double dx;
 extern double dy;

 int i,j;

 Matrix Output = InitialGuess; 
 
 int Iteration = 0;
 double Error = 2*Tolerance;

 double SelectionRatio = 0.25;
 double SelectionCriterion = Tolerance; 

 SolverPoint* pHeadSolverPoint = NULL;
 SolverPoint* pCurrentSolverPoint = pHeadSolverPoint;

 int MaxSolverPoints = ( X.TellCols() * Y.TellCols() )/4; 
 MaxSolverPoints = 10 * X.TellCols();
 int NumberOfSolverPoints = 0;
 
 bool GiveUp = false;
 int GiveUpThreshold = (int) floor( (0.015*X.TellCols())*(0.015*Y.TellCols()) );
 
 int SweepDirectionI,SweepDirectionJ;
 int StartI,EndI;
 int StartJ,EndJ;
 
 Iteration_Change_Matrix  = zeros( X.TellCols() , Y.TellCols() );

 int k=0;
 
 double mean_change = 0.0;
 double change_variance = 9e9;
 
 double change_variance_tolerance = 0.000001*Tolerance;
 if( change_variance_tolerance < 1e-14 )
 { change_variance_tolerance = 1e-14; }
 
 while( Iteration < MaxIterations && Error > Tolerance && change_variance > change_variance_tolerance )
 {
  mean_change = 0.0;
  double Number_of_nodes = ( X.TellCols()-2.0 )*( Y.TellCols() - 2.0 );
 
  // Set the sweep directions
  if( k % 4 == 0 )
  { 
   SweepDirectionI = 1;
   StartI = 1;
   EndI = InitialGuess.TellRows()-1;
   
   SweepDirectionJ = 1;
   StartJ = 1;
   EndJ = InitialGuess.TellCols()-1;
  }
  if( k % 4 == 1 )
  { 
   SweepDirectionI = -1;
   EndI = 0;
   StartI = InitialGuess.TellRows()-2;
   
   SweepDirectionJ = 1;
   StartJ = 1;
   EndJ = InitialGuess.TellCols()-1;
  }
  if( k % 4 == 2 )
  { 
   SweepDirectionI = 1;
   StartI = 1;
   EndI = InitialGuess.TellRows()-1;
   
   SweepDirectionJ = -1;
   EndJ = 0;
   StartJ = InitialGuess.TellCols()-2;
  }
  if( k % 4 == 3 )
  { 
   SweepDirectionI = -1;
   EndI = 0;
   StartI = InitialGuess.TellRows()-2;
   
   SweepDirectionJ = -1;
   EndJ = 0;
   StartJ = InitialGuess.TellCols()-2;
  }
  
  // update the boundary points
  
  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   j=Y.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
   i=X.TellCols()-1;
   *Output(i,j) = gfmUpdateBoundaryPoint( X,Y,Output,LeftBC,LeftBCtype,
                                       RightBC,RightBCtype,BottomBC,BottomBCtype,
									   TopBC,TopBCtype,i,j); 
  }			

  // sweep and note the maximum
  
  Error = 0.0;
  i = StartI;
  while( i != EndI )
  {
   j = StartJ;
   while( j != EndJ )
   {
    double NewValue = gfmUpdateFunction(X,Y,Phi,Output, 
	 Diffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	double change = fabs( NewValue - *Output(i,j) );
	*Iteration_Change_Matrix(i,j) = change; 
	mean_change += change;
	
	if( change > Error )
	{ Error = change; }
	*Output(i,j) = NewValue;
	j += SweepDirectionJ;
   }
   i += SweepDirectionI;
  }
  Iteration++;
  
  mean_change /= Number_of_nodes;
  change_variance = 0.0;
  for( int ii=1 ; ii < Iteration_Change_Matrix.TellRows()-1 ; ii++ )
  {
   for( int jj=1 ; jj < Iteration_Change_Matrix.TellCols()-1 ; jj++ )
   {
    change_variance += square( *Iteration_Change_Matrix(ii,jj) - mean_change );
   }
  }  
  change_variance /= Number_of_nodes;
//  cout << mean_change << " +/- " << change_variance << endl;
  
   // create the selection criterion 
   
   SelectionCriterion = SelectionRatio*Error;
   pCurrentSolverPoint = pHeadSolverPoint;
   NumberOfSolverPoints = 0;
   
   // sweep and create the list  
   
   i = StartI;  
   while( i != EndI )
   {
    j = StartJ;
    while( j != EndJ )
    {
     double NewValue = gfmUpdateFunction(X,Y,Phi,Output, 
	  Diffusivity,
	  SourceFunction,SourceFunctionU,
	  JumpCondition,NormalJumpCondition,i,j,dx,dy);
	  
	 double change = fabs( NewValue - *Output(i,j) );
	 *Output(i,j) = NewValue;
	 
	 if( change > SelectionCriterion && NumberOfSolverPoints < MaxSolverPoints  )
	 {
      SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 j += SweepDirectionJ;
    }
    i += SweepDirectionI;
   }
   Iteration++;
  
   // sweep over the list 
   
   int ListIteration = 0;
   double TempError = 2.0*SelectionCriterion; 
   int MaxInternalIterations = 2;
   while( ListIteration < MaxInternalIterations && 
          TempError > 0.99*SelectionCriterion && 
		  TempError < 1 )
   {
    pCurrentSolverPoint = pHeadSolverPoint;
    TempError = 0.0;
    while( pCurrentSolverPoint )
    {
     i = pCurrentSolverPoint->i;
 	 j = pCurrentSolverPoint->j;
     double NewValue = gfmUpdateFunction(X,Y,Phi,Output, 
	  Diffusivity,
	  SourceFunction,SourceFunctionU,
	  JumpCondition,NormalJumpCondition,i,j,dx,dy);
	  
	 double change = fabs( NewValue - *Output(i,j) );
	 if( change > TempError )
	 { TempError = change; }
	 *Output(i,j) = NewValue;   
     
     pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint;
    }
    ListIteration++;
   }
   
   // delete the list
 
   pCurrentSolverPoint = pHeadSolverPoint;  
   while( pHeadSolverPoint )
   {
    pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
    delete pHeadSolverPoint;
    pHeadSolverPoint = pCurrentSolverPoint;
   }

  if( Iteration % 1000 == 0 )
  { cout << Iteration << " : " << Error << endl; }  

  k++;
 }
 cout << "summary:: iterations: " << Iteration << endl
      << "          error     : " << Error << endl << endl;
 if( GiveUp )
 {
  cout << "Gave up because adaptivity was being focused on less than 0.0225% of nodes!" << endl
       << "(" << NumberOfSolverPoints << " nodes)" << endl << endl; 
 } 
 return Output;
} 


void WithOxygenWTGhostFluidMethod_Generic_MatrixForm(Matrix& X, Matrix& Y, Matrix& Phi, 
   Matrix& Diffusivity, 
   Matrix& SourceFunction, Matrix& SourceFunctionU, 
   double (*PLeftBC)(double),   char PLeftBCtype,  
   double (*PRightBC)(double),  char PRightBCtype,     
   double (*PBottomBC)(double), char PBottomBCtype,   
   double (*PTopBC)(double),    char PTopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double), double PTolerance,
  /* Matrix& InitialGuess, */ 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*DiffusionConstant)(double,double,double,int,int), 
   double (*SourceTimesU)(double,double,double,int,int),
   double (*SourceRemainder)(double,double,double,int,int),
   int MaxIterations, double OTolerance ,
   double ImplicitUpdate(
Matrix& Solution, 
double (*Diffusion)(double,double,double,int,int),
double (*SourceTimesU)(double,double,double,int,int),
double (*SourceRemainder)(double,double,double,int,int), 
int i, int j, 
double x, double y, double dx, double dy ),
/*
double UpdateBoundaryPoint( Matrix& Solution, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   int i, int j, 
   double x, double y )*/
double UpdateBoundaryPoint(Matrix& Solution, 
double (*Diffusion)(double,double,double,int,int),
double (*SourceTimesU)(double,double,double,int,int),
double (*SourceRemainder)(double,double,double,int,int), 
int i, int j, 
double x, double y, double dx, double dy),double WTolerance,
double AngioFluidPressureUpdate( Matrix& Diffusion,  Matrix& BloodNodePressure, Matrix& Pressure, Matrix& Solution, Matrix& CellSource,  int i, int j),
double FluidPressureUpdateBoundaryPoint( Matrix& Diffusion,  Matrix& BloodNodePressure, Matrix& Pressure, Matrix& Solution,   int i, int j)

)
{
 extern double dx;
 extern double dy;
 extern bool AdaptionBegin;
 extern double QuiescenceOxygenLevel;
 int i,j;

 //Matrix Output = InitialGuess; 
 extern Matrix Oxygen,Pressure, InterPressure, BloodNodePressure;
 extern Matrix Phi, PhiQuiescent, PhiNecrotic;
 extern double TracerMax;
 extern double _EPS;
 extern double TumorProliferationConstant;
 extern double ApoptosisRate;
 extern double DRG_Effect;
 extern Matrix TracerD;
 int Iteration = 0;
 double PError = 2*PTolerance;
 double OError = 2*OTolerance;
 double WError = 2*WTolerance;

 double SelectionRatio = 0.25;
 double SelectionOCriterion = OTolerance;
 double SelectionPCriterion = PTolerance; 
 double SelectionWCriterion = WTolerance; 

 SolverPoint* pHeadSolverPoint = NULL;
 SolverPoint* pCurrentSolverPoint = pHeadSolverPoint;

 int MaxSolverPoints = ( X.TellCols() * Y.TellCols() )/4; 
 MaxSolverPoints = 10 * X.TellCols();
 int NumberOfSolverPoints = 0;
 
 bool GiveUp = false;
 int GiveUpThreshold = (int) floor( (0.015*X.TellCols())*(0.015*Y.TellCols()) );
 
 int SweepDirectionI,SweepDirectionJ;
 int StartI,EndI;
 int StartJ,EndJ;
 
 Iteration_Change_Matrix  = zeros( X.TellCols() , Y.TellCols() );

 int k=0;
 
 double mean_change = 0.0;
 double change_variance = 9e9;
	extern char* ParameterFile;
	extern double CondTissue;
	Matrix AdvectConstant = ones(X.TellCols(),Y.TellCols());
	for(int ii=0; ii<X.TellCols(); ii++)
	{
		for(int jj=0; jj<Y.TellCols(); jj++)
		{
			//cout<<*BloodVesselIndicatorX(ii,jj)<<endl;
			*AdvectConstant(ii,jj) = CondTissue;
		}
	}
 
 double change_variance_tolerance = 0.000001*PTolerance;
 if( change_variance_tolerance < 1e-14 )
 { change_variance_tolerance = 1e-14; }
 ////////////////////////
// if(AdaptionBegin==1)
// {
//  Pressure = zeros( X.TellCols() , Y.TellCols() );
// Oxygen = ones( X.TellCols() , Y.TellCols() );
// }
 ///////////////////////
 while( Iteration < MaxIterations && (WError > WTolerance ||OError > OTolerance || PError > PTolerance && change_variance > change_variance_tolerance))
 {
  mean_change = 0.0;
  double Number_of_nodes = ( X.TellCols()-2.0 )*( Y.TellCols() - 2.0 );
 
  // Set the sweep directions
  if( k % 4 == 0 )
  { 
   SweepDirectionI = 1;
   StartI = 1;
   EndI = Oxygen.TellRows()-1;
   
   SweepDirectionJ = 1;
   StartJ = 1;
   EndJ = Oxygen.TellCols()-1;
  }
  if( k % 4 == 1 )
  { 
   SweepDirectionI = -1;
   EndI = 0;
   StartI = Oxygen.TellRows()-2;
   
   SweepDirectionJ = 1;
   StartJ = 1;
   EndJ = Oxygen.TellCols()-1;
  }
  if( k % 4 == 2 )
  { 
   SweepDirectionI = 1;
   StartI = 1;
   EndI = Oxygen.TellRows()-1;
   
   SweepDirectionJ = -1;
   EndJ = 0;
   StartJ = Oxygen.TellCols()-2;
  }
  if( k % 4 == 3 )
  { 
   SweepDirectionI = -1;
   EndI = 0;
   StartI = Oxygen.TellRows()-2;
   
   SweepDirectionJ = -1;
   EndJ = 0;
   StartJ = Oxygen.TellCols()-2;
  }
  
  // update the boundary points
  
  for( i=0 ; i < X.TellCols() ; i++ )
  {
   j=0;
   
									   
   double  ONewValue = UpdateBoundaryPoint( Oxygen, DiffusionConstant, SourceTimesU, SourceRemainder, i,j,*X(i),*Y(j),dx,dy );

   double Ochange = fabs( ONewValue - *Oxygen(i,j) );
   if( Ochange > OError )
   { OError = Ochange; }
   *Oxygen(i,j) = ONewValue; 
   

  

   *Pressure(i,j) = gfmUpdateBoundaryPoint( X,Y,Pressure,PLeftBC,PLeftBCtype,
                                       PRightBC,PRightBCtype,PBottomBC,PBottomBCtype,
									   PTopBC,PTopBCtype,i,j); 
	*InterPressure(i,j) = FluidPressureUpdateBoundaryPoint( AdvectConstant,  BloodNodePressure, Pressure, InterPressure, i, j);
	  
	  
	  
   
   j=Y.TellCols()-1;
       ONewValue = UpdateBoundaryPoint( Oxygen, DiffusionConstant, SourceTimesU, SourceRemainder, i,j,*X(i),*Y(j),dx,dy );


   Ochange = fabs( ONewValue - *Oxygen(i,j) );
   if( Ochange > OError )
   { OError = Ochange; }
   *Oxygen(i,j) = ONewValue; 
   
  

    *Pressure(i,j) = gfmUpdateBoundaryPoint( X,Y,Pressure,PLeftBC,PLeftBCtype,
                                       PRightBC,PRightBCtype,PBottomBC,PBottomBCtype,
									   PTopBC,PTopBCtype,i,j); 
  *InterPressure(i,j) = FluidPressureUpdateBoundaryPoint( AdvectConstant,  BloodNodePressure, Pressure, InterPressure, i, j);		
	 // cout<<*InterPressure(i,j)<<endl;
	  //getchar();


  }									   
  for( j = 1 ; j < Y.TellCols()-1 ; j++ )
  {
   i=0;
   /*
  double ONewValue = UpdateBoundaryPoint(Oxygen,
                                         LeftBC,LeftBCtype, 
                                         RightBC,RightBCtype,
										 BottomBC,BottomBCtype,
										 TopBC,TopBCtype,
   										 i,j,*X(i),*Y(j));
										 */
  double ONewValue = UpdateBoundaryPoint( Oxygen, DiffusionConstant, SourceTimesU, SourceRemainder, i,j,*X(i),*Y(j),dx,dy );
   double Ochange = fabs( ONewValue - *Oxygen(i,j) );
   if( Ochange > OError )
   { OError = Ochange; }
   *Oxygen(i,j) = ONewValue; 
   

     *Pressure(i,j) = gfmUpdateBoundaryPoint( X,Y,Pressure,PLeftBC,PLeftBCtype,
                                       PRightBC,PRightBCtype,PBottomBC,PBottomBCtype,
									   PTopBC,PTopBCtype,i,j); 
	  *InterPressure(i,j) = FluidPressureUpdateBoundaryPoint( AdvectConstant,  BloodNodePressure,Pressure, InterPressure, i, j);
									   

   
   i=X.TellCols()-1;
   
									   
   ONewValue = UpdateBoundaryPoint( Oxygen, DiffusionConstant, SourceTimesU, SourceRemainder, i,j,*X(i),*Y(j),dx,dy );


   Ochange = fabs( ONewValue - *Oxygen(i,j) );
   if( Ochange > OError )
   { OError = Ochange; }
   *Oxygen(i,j) = ONewValue; 
   
   
    *Pressure(i,j) = gfmUpdateBoundaryPoint( X,Y,Pressure,PLeftBC,PLeftBCtype,
                                       PRightBC,PRightBCtype,PBottomBC,PBottomBCtype,
									   PTopBC,PTopBCtype,i,j); 
	  *InterPressure(i,j) = FluidPressureUpdateBoundaryPoint( AdvectConstant,  BloodNodePressure, Pressure, InterPressure, i, j);

  }			

  // sweep and note the maximum
  
  PError = 0.0;
  OError = 0.0;
  WError = 0.0;
  i = StartI;
  while( i != EndI )
  {
   j = StartJ;
   while( j != EndJ )
   {
    double ONewValue = ImplicitUpdate( Oxygen, 
                                       DiffusionConstant, SourceTimesU, SourceRemainder, 
                                       i,j,*X(i),*Y(j),dx,dy );
	 
     double Ochange = fabs( ONewValue - *Oxygen(i,j) );
     if( Ochange > OError )
     { OError = Ochange; } 
     *Oxygen(i,j) = ONewValue; 
	   
	   
	  
	 if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)>QuiescenceOxygenLevel )
   {
    *SourceFunction(i,j) =  TumorProliferationConstant*( *Oxygen(i,j)*(1-DRG_Effect* *TracerD(i,j)*TracerMax) - ApoptosisRate);

   }
   
    if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)<=QuiescenceOxygenLevel )
   {
    *SourceFunction(i,j) =  0.0;
   }

   
    double PNewValue = gfmImplicitUpdateContinuousD_MatrixForm(X,Y,Phi,Pressure, 
	 Diffusivity,
	 SourceFunction,SourceFunctionU,
	 JumpCondition,NormalJumpCondition,i,j,dx,dy);
	 
	double Pchange = fabs( PNewValue - *Pressure(i,j) );
	*Iteration_Change_Matrix(i,j) = Pchange; 
	mean_change += Pchange;
	
	if( Pchange > PError )
	{ PError = Pchange; }
	*Pressure(i,j) = PNewValue;
	   
	  
	   
	   double WNewValue = AngioFluidPressureUpdate( AdvectConstant,  BloodNodePressure, Pressure,  InterPressure, SourceFunction,  i, j);
	   
	   double Wchange = fabs( WNewValue - *InterPressure(i,j) );
	   if( Wchange > WError )
	   { WError = Wchange; } 
	   *InterPressure(i,j) = WNewValue; 
	   
	   
	   
	   
	j += SweepDirectionJ;
   }
   i += SweepDirectionI;
  }
  Iteration++;
  
  mean_change /= Number_of_nodes;
  change_variance = 0.0;
  for( int ii=1 ; ii < Iteration_Change_Matrix.TellRows()-1 ; ii++ )
  {
   for( int jj=1 ; jj < Iteration_Change_Matrix.TellCols()-1 ; jj++ )
   {
    change_variance += square( *Iteration_Change_Matrix(ii,jj) - mean_change );
   }
  }  
  change_variance /= Number_of_nodes;
//  cout << mean_change << " +/- " << change_variance << endl;
  
   // create the selection criterion 
   SelectionOCriterion = SelectionRatio*OError;
   SelectionPCriterion = SelectionRatio*PError;
   SelectionWCriterion = SelectionRatio*WError;
   pCurrentSolverPoint = pHeadSolverPoint;
   NumberOfSolverPoints = 0;
   
   // sweep and create the list  
   
   i = StartI;  
   while( i != EndI )
   {
    j = StartJ;
    while( j != EndJ )
    {
	
	 double ONewValue = ImplicitUpdate( Oxygen, 
                                       DiffusionConstant, SourceTimesU, SourceRemainder, 
                                       i,j,*X(i),*Y(j),dx,dy );
     double Ochange = fabs( ONewValue - *Oxygen(i,j) );
     if( Ochange > OError )
     { OError = Ochange; } 
     *Oxygen(i,j) = ONewValue; 
	 
	 if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)>QuiescenceOxygenLevel )
   {
    *SourceFunction(i,j) =  TumorProliferationConstant*( *Oxygen(i,j)*(1-DRG_Effect* *TracerD(i,j)*TracerMax) - ApoptosisRate);
   }
   
    if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)<=QuiescenceOxygenLevel )
   {
    *SourceFunction(i,j) =  0.0;
   }
     double PNewValue = gfmImplicitUpdateContinuousD_MatrixForm(X,Y,Phi,Pressure, 
	  Diffusivity,
	  SourceFunction,SourceFunctionU,
	  JumpCondition,NormalJumpCondition,i,j,dx,dy);
	  
	 double Pchange = fabs( PNewValue - *Pressure(i,j) );
	 *Pressure(i,j) = PNewValue;
		double WNewValue = AngioFluidPressureUpdate( AdvectConstant,  BloodNodePressure, Pressure, InterPressure, SourceFunction,  i, j);
		
		double Wchange = fabs( WNewValue - *InterPressure(i,j) );
		if( Wchange > WError )
		{ WError = Wchange; } 
		*InterPressure(i,j) = WNewValue; 
	/** 
	 if( (Pchange > SelectionPCriterion || Ochange > SelectionOCriterion)&& NumberOfSolverPoints < MaxSolverPoints  )
	 {
      SolverPoint* pNewSolverPoint;
	  pNewSolverPoint = new SolverPoint; 
	  pNewSolverPoint->i = i;
	  pNewSolverPoint->j = j;
	  NumberOfSolverPoints++;
	  if( pCurrentSolverPoint )
	  { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
	  else
	  { pHeadSolverPoint = pNewSolverPoint; }
	  pCurrentSolverPoint = pNewSolverPoint; 
	 }
	 
	 **/
	 j += SweepDirectionJ;
    }
    i += SweepDirectionI;
   }
   
   Iteration++;
  
   // sweep over the list 
   
   int ListIteration = 0;
   double TempOError = 2.0*SelectionOCriterion;
   double TempPError = 2.0*SelectionPCriterion; 
   double TempWError = 2.0*SelectionWCriterion;
   /*********
   int MaxInternalIterations = 2;
   while( ListIteration < MaxInternalIterations && 
         ( TempPError > 0.99*SelectionPCriterion && 
		  TempPError < 1 ||TempOError > 0.99*SelectionOCriterion && 
		  TempOError < 1 ))
   {
    pCurrentSolverPoint = pHeadSolverPoint;
	TempOError = 0.0;
    TempPError = 0.0;
    while( pCurrentSolverPoint )
    {
     i = pCurrentSolverPoint->i;
 	 j = pCurrentSolverPoint->j;
	 
	 double ONewValue = ImplicitUpdate( Oxygen, 
                                      DiffusionConstant, SourceTimesU, SourceRemainder, 
                                      i,j,*X(i),*Y(j),dx,dy );
     *Oxygen(i,j) = ONewValue; 
	 
	 double Ochange = fabs( ONewValue - *Oxygen(i,j) );
     if( Ochange > TempOError )
     { TempOError = Ochange; } 
     *Oxygen(i,j) = ONewValue; 
	 
	 if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)>QuiescenceOxygenLevel )
   {
    *SourceFunction(i,j) =  TumorProliferationConstant*( *Oxygen(i,j) - ApoptosisRate);
   }
   
    if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)<=QuiescenceOxygenLevel )
   {
    *SourceFunction(i,j) =  0.0;
   }

     double PNewValue = gfmImplicitUpdateContinuousD_MatrixForm(X,Y,Phi,Pressure, 
	  Diffusivity,
	  SourceFunction,SourceFunctionU,
	  JumpCondition,NormalJumpCondition,i,j,dx,dy);
	  
	 double Pchange = fabs( PNewValue - *Pressure(i,j) );
	 if( Pchange > TempPError )
	 { TempPError = Pchange; }
	 *Pressure(i,j) = PNewValue;   
     
     pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint;
    }
    ListIteration++;
   }
   ***/
   // delete the list
 
   pCurrentSolverPoint = pHeadSolverPoint;  
   while( pHeadSolverPoint )
   {
    pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
    delete pHeadSolverPoint;
    pHeadSolverPoint = pCurrentSolverPoint;
   }

  if( Iteration % 1000 == 0 )
  { cout << Iteration << " : " << WError << endl;
  cout << Iteration << " : " << PError << endl;
  cout << Iteration << " : " << OError << endl;
  
  }  

  k++;
 }
 cout << "summary:: iterations: " << Iteration << endl
      << "          WError     : " << WError << endl << endl;
 if( GiveUp )
 {
  cout << "Gave up because adaptivity was being focused on less than 0.0225% of nodes!" << endl
       << "(" << NumberOfSolverPoints << " nodes)" << endl << endl; 
 } 
 
} 
void WithOxygenGhostFluidMethod_Generic_MatrixForm(Matrix& X, Matrix& Y, Matrix& Phi, 
												   Matrix& Diffusivity, 
												   Matrix& SourceFunction, Matrix& SourceFunctionU, 
												   double (*PLeftBC)(double),   char PLeftBCtype,  
												   double (*PRightBC)(double),  char PRightBCtype,     
												   double (*PBottomBC)(double), char PBottomBCtype,   
												   double (*PTopBC)(double),    char PTopBCtype,  
												   double (*JumpCondition)(double,double), 
												   double (*NormalJumpCondition)(double,double), double PTolerance,
												   /* Matrix& InitialGuess, */ 
												   double (*LeftBC)(double),   char LeftBCtype,  
												   double (*RightBC)(double),  char RightBCtype,     
												   double (*BottomBC)(double), char BottomBCtype,   
												   double (*TopBC)(double),    char TopBCtype,  
												   double (*DiffusionConstant)(double,double,double,int,int), 
												   double (*SourceTimesU)(double,double,double,int,int),
												   double (*SourceRemainder)(double,double,double,int,int),
												   int MaxIterations, double OTolerance ,
												   double ImplicitUpdate(
																		 Matrix& Solution, 
																		 double (*Diffusion)(double,double,double,int,int),
																		 double (*SourceTimesU)(double,double,double,int,int),
																		 double (*SourceRemainder)(double,double,double,int,int), 
																		 int i, int j, 
																		 double x, double y, double dx, double dy ),
												   double UpdateBoundaryPoint(Matrix& Solution, 
																			  double (*Diffusion)(double,double,double,int,int),
																			  double (*SourceTimesU)(double,double,double,int,int),
																			  double (*SourceRemainder)(double,double,double,int,int), 
																			  int i, int j, 
																			  double x, double y, double dx, double dy)
												   
												   )
{
	extern double dx;
	extern double dy;
	extern bool AdaptionBegin;
	extern double QuiescenceOxygenLevel;
	int i,j;
	
	//Matrix Output = InitialGuess; 
	extern Matrix Oxygen,Pressure;
	extern Matrix Phi, PhiQuiescent, PhiNecrotic;
	extern double TracerMax;
	extern double _EPS;
	extern double TumorProliferationConstant;
	extern double ApoptosisRate;
	extern double DRG_Effect;
	extern Matrix TracerD;
	int Iteration = 0;
	double PError = 2*PTolerance;
	double OError = 2*OTolerance;
	
	double SelectionRatio = 0.25;
	double SelectionOCriterion = OTolerance;
	double SelectionPCriterion = PTolerance; 
	
	SolverPoint* pHeadSolverPoint = NULL;
	SolverPoint* pCurrentSolverPoint = pHeadSolverPoint;
	
	int MaxSolverPoints = ( X.TellCols() * Y.TellCols() )/4; 
	MaxSolverPoints = 10 * X.TellCols();
	int NumberOfSolverPoints = 0;
	
	bool GiveUp = false;
	int GiveUpThreshold = (int) floor( (0.015*X.TellCols())*(0.015*Y.TellCols()) );
	
	int SweepDirectionI,SweepDirectionJ;
	int StartI,EndI;
	int StartJ,EndJ;
	
	Iteration_Change_Matrix  = zeros( X.TellCols() , Y.TellCols() );
	
	int k=0;
	
	double mean_change = 0.0;
	double change_variance = 9e9;
	
	double change_variance_tolerance = 0.000001*PTolerance;
	if( change_variance_tolerance < 1e-14 )
	{ change_variance_tolerance = 1e-14; }
	////////////////////////
	// if(AdaptionBegin==1)
	// {
	//  Pressure = zeros( X.TellCols() , Y.TellCols() );
	// Oxygen = ones( X.TellCols() , Y.TellCols() );
	// }
	///////////////////////
	while( Iteration < MaxIterations && (OError > OTolerance || PError > PTolerance && change_variance > change_variance_tolerance))
	{
		mean_change = 0.0;
		double Number_of_nodes = ( X.TellCols()-2.0 )*( Y.TellCols() - 2.0 );
		
		// Set the sweep directions
		if( k % 4 == 0 )
		{ 
			SweepDirectionI = 1;
			StartI = 1;
			EndI = Oxygen.TellRows()-1;
			
			SweepDirectionJ = 1;
			StartJ = 1;
			EndJ = Oxygen.TellCols()-1;
		}
		if( k % 4 == 1 )
		{ 
			SweepDirectionI = -1;
			EndI = 0;
			StartI = Oxygen.TellRows()-2;
			
			SweepDirectionJ = 1;
			StartJ = 1;
			EndJ = Oxygen.TellCols()-1;
		}
		if( k % 4 == 2 )
		{ 
			SweepDirectionI = 1;
			StartI = 1;
			EndI = Oxygen.TellRows()-1;
			
			SweepDirectionJ = -1;
			EndJ = 0;
			StartJ = Oxygen.TellCols()-2;
		}
		if( k % 4 == 3 )
		{ 
			SweepDirectionI = -1;
			EndI = 0;
			StartI = Oxygen.TellRows()-2;
			
			SweepDirectionJ = -1;
			EndJ = 0;
			StartJ = Oxygen.TellCols()-2;
		}
		
		// update the boundary points
		
		for( i=0 ; i < X.TellCols() ; i++ )
		{
			j=0;
			
			
			double  ONewValue = UpdateBoundaryPoint( Oxygen, DiffusionConstant, SourceTimesU, SourceRemainder, i,j,*X(i),*Y(j),dx,dy );
			
			double Ochange = fabs( ONewValue - *Oxygen(i,j) );
			if( Ochange > OError )
			{ OError = Ochange; }
			*Oxygen(i,j) = ONewValue; 
			
			
			
			
			*Pressure(i,j) = gfmUpdateBoundaryPoint( X,Y,Pressure,PLeftBC,PLeftBCtype,
													PRightBC,PRightBCtype,PBottomBC,PBottomBCtype,
													PTopBC,PTopBCtype,i,j); 
			
			j=Y.TellCols()-1;
			ONewValue = UpdateBoundaryPoint( Oxygen, DiffusionConstant, SourceTimesU, SourceRemainder, i,j,*X(i),*Y(j),dx,dy );
			
			
			Ochange = fabs( ONewValue - *Oxygen(i,j) );
			if( Ochange > OError )
			{ OError = Ochange; }
			*Oxygen(i,j) = ONewValue; 
			
			
			
			*Pressure(i,j) = gfmUpdateBoundaryPoint( X,Y,Pressure,PLeftBC,PLeftBCtype,
													PRightBC,PRightBCtype,PBottomBC,PBottomBCtype,
													PTopBC,PTopBCtype,i,j); 
			
			
			
		}									   
		for( j = 1 ; j < Y.TellCols()-1 ; j++ )
		{
			i=0;
			/*
			 double ONewValue = UpdateBoundaryPoint(Oxygen,
			 LeftBC,LeftBCtype, 
			 RightBC,RightBCtype,
			 BottomBC,BottomBCtype,
			 TopBC,TopBCtype,
			 i,j,*X(i),*Y(j));
			 */
			double ONewValue = UpdateBoundaryPoint( Oxygen, DiffusionConstant, SourceTimesU, SourceRemainder, i,j,*X(i),*Y(j),dx,dy );
			double Ochange = fabs( ONewValue - *Oxygen(i,j) );
			if( Ochange > OError )
			{ OError = Ochange; }
			*Oxygen(i,j) = ONewValue; 
			
			
			*Pressure(i,j) = gfmUpdateBoundaryPoint( X,Y,Pressure,PLeftBC,PLeftBCtype,
													PRightBC,PRightBCtype,PBottomBC,PBottomBCtype,
													PTopBC,PTopBCtype,i,j); 
			
			
			
			i=X.TellCols()-1;
			
			
			ONewValue = UpdateBoundaryPoint( Oxygen, DiffusionConstant, SourceTimesU, SourceRemainder, i,j,*X(i),*Y(j),dx,dy );
			
			
			Ochange = fabs( ONewValue - *Oxygen(i,j) );
			if( Ochange > OError )
			{ OError = Ochange; }
			*Oxygen(i,j) = ONewValue; 
			
			
			*Pressure(i,j) = gfmUpdateBoundaryPoint( X,Y,Pressure,PLeftBC,PLeftBCtype,
													PRightBC,PRightBCtype,PBottomBC,PBottomBCtype,
													PTopBC,PTopBCtype,i,j); 
			
		}			
		
		// sweep and note the maximum
		
		PError = 0.0;
		OError = 0.0;
		i = StartI;
		while( i != EndI )
		{
			j = StartJ;
			while( j != EndJ )
			{
				double ONewValue = ImplicitUpdate( Oxygen, 
												  DiffusionConstant, SourceTimesU, SourceRemainder, 
												  i,j,*X(i),*Y(j),dx,dy );
				
				double Ochange = fabs( ONewValue - *Oxygen(i,j) );
				if( Ochange > OError )
				{ OError = Ochange; } 
				*Oxygen(i,j) = ONewValue; 
				
				if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)>QuiescenceOxygenLevel )
				{
					*SourceFunction(i,j) =  TumorProliferationConstant*( *Oxygen(i,j)*(1-DRG_Effect* *TracerD(i,j)*TracerMax) - ApoptosisRate);
					
				}
				
				if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)<=QuiescenceOxygenLevel )
				{
					*SourceFunction(i,j) =  0.0;
				}
				
				
				double PNewValue = gfmImplicitUpdateContinuousD_MatrixForm(X,Y,Phi,Pressure, 
																		   Diffusivity,
																		   SourceFunction,SourceFunctionU,
																		   JumpCondition,NormalJumpCondition,i,j,dx,dy);
				
				double Pchange = fabs( PNewValue - *Pressure(i,j) );
				*Iteration_Change_Matrix(i,j) = Pchange; 
				mean_change += Pchange;
				
				if( Pchange > PError )
				{ PError = Pchange; }
				*Pressure(i,j) = PNewValue;
				j += SweepDirectionJ;
			}
			i += SweepDirectionI;
		}
		Iteration++;
		
		mean_change /= Number_of_nodes;
		change_variance = 0.0;
		for( int ii=1 ; ii < Iteration_Change_Matrix.TellRows()-1 ; ii++ )
		{
			for( int jj=1 ; jj < Iteration_Change_Matrix.TellCols()-1 ; jj++ )
			{
				change_variance += square( *Iteration_Change_Matrix(ii,jj) - mean_change );
			}
		}  
		change_variance /= Number_of_nodes;
		//  cout << mean_change << " +/- " << change_variance << endl;
		
		// create the selection criterion 
		SelectionOCriterion = SelectionRatio*OError;
		SelectionPCriterion = SelectionRatio*PError;
		pCurrentSolverPoint = pHeadSolverPoint;
		NumberOfSolverPoints = 0;
		
		// sweep and create the list  
		
		i = StartI;  
		while( i != EndI )
		{
			j = StartJ;
			while( j != EndJ )
			{
				
				double ONewValue = ImplicitUpdate( Oxygen, 
												  DiffusionConstant, SourceTimesU, SourceRemainder, 
												  i,j,*X(i),*Y(j),dx,dy );
				double Ochange = fabs( ONewValue - *Oxygen(i,j) );
				if( Ochange > OError )
				{ OError = Ochange; } 
				*Oxygen(i,j) = ONewValue; 
				
				if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)>QuiescenceOxygenLevel )
				{
					*SourceFunction(i,j) =  TumorProliferationConstant*( *Oxygen(i,j)*(1-DRG_Effect* *TracerD(i,j)*TracerMax) - ApoptosisRate);
				}
				
				if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)<=QuiescenceOxygenLevel )
				{
					*SourceFunction(i,j) =  0.0;
				}
				double PNewValue = gfmImplicitUpdateContinuousD_MatrixForm(X,Y,Phi,Pressure, 
																		   Diffusivity,
																		   SourceFunction,SourceFunctionU,
																		   JumpCondition,NormalJumpCondition,i,j,dx,dy);
				
				double Pchange = fabs( PNewValue - *Pressure(i,j) );
				*Pressure(i,j) = PNewValue;
				/** 
				 if( (Pchange > SelectionPCriterion || Ochange > SelectionOCriterion)&& NumberOfSolverPoints < MaxSolverPoints  )
				 {
				 SolverPoint* pNewSolverPoint;
				 pNewSolverPoint = new SolverPoint; 
				 pNewSolverPoint->i = i;
				 pNewSolverPoint->j = j;
				 NumberOfSolverPoints++;
				 if( pCurrentSolverPoint )
				 { pCurrentSolverPoint->pNextSolverPoint = pNewSolverPoint; }
				 else
				 { pHeadSolverPoint = pNewSolverPoint; }
				 pCurrentSolverPoint = pNewSolverPoint; 
				 }
				 
				 **/
				j += SweepDirectionJ;
			}
			i += SweepDirectionI;
		}
		
		Iteration++;
		
		// sweep over the list 
		
		int ListIteration = 0;
		double TempOError = 2.0*SelectionOCriterion;
		double TempPError = 2.0*SelectionPCriterion; 
		/*********
		 int MaxInternalIterations = 2;
		 while( ListIteration < MaxInternalIterations && 
         ( TempPError > 0.99*SelectionPCriterion && 
		 TempPError < 1 ||TempOError > 0.99*SelectionOCriterion && 
		 TempOError < 1 ))
		 {
		 pCurrentSolverPoint = pHeadSolverPoint;
		 TempOError = 0.0;
		 TempPError = 0.0;
		 while( pCurrentSolverPoint )
		 {
		 i = pCurrentSolverPoint->i;
		 j = pCurrentSolverPoint->j;
		 
		 double ONewValue = ImplicitUpdate( Oxygen, 
		 DiffusionConstant, SourceTimesU, SourceRemainder, 
		 i,j,*X(i),*Y(j),dx,dy );
		 *Oxygen(i,j) = ONewValue; 
		 
		 double Ochange = fabs( ONewValue - *Oxygen(i,j) );
		 if( Ochange > TempOError )
		 { TempOError = Ochange; } 
		 *Oxygen(i,j) = ONewValue; 
		 
		 if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)>QuiescenceOxygenLevel )
		 {
		 *SourceFunction(i,j) =  TumorProliferationConstant*( *Oxygen(i,j) - ApoptosisRate);
		 }
		 
		 if( *Phi(i,j) <= _EPS && *PhiNecrotic(i,j)>_EPS && *Oxygen(i,j)<=QuiescenceOxygenLevel )
		 {
		 *SourceFunction(i,j) =  0.0;
		 }
		 
		 double PNewValue = gfmImplicitUpdateContinuousD_MatrixForm(X,Y,Phi,Pressure, 
		 Diffusivity,
		 SourceFunction,SourceFunctionU,
		 JumpCondition,NormalJumpCondition,i,j,dx,dy);
		 
		 double Pchange = fabs( PNewValue - *Pressure(i,j) );
		 if( Pchange > TempPError )
		 { TempPError = Pchange; }
		 *Pressure(i,j) = PNewValue;   
		 
		 pCurrentSolverPoint = pCurrentSolverPoint->pNextSolverPoint;
		 }
		 ListIteration++;
		 }
		 ***/
		// delete the list
		
		pCurrentSolverPoint = pHeadSolverPoint;  
		while( pHeadSolverPoint )
		{
			pCurrentSolverPoint = pHeadSolverPoint->pNextSolverPoint;
			delete pHeadSolverPoint;
			pHeadSolverPoint = pCurrentSolverPoint;
		}
		
		if( Iteration % 1000 == 0 )
		{ cout << Iteration << " : " << PError << endl; }  
		
		k++;
	}
	cout << "summary:: iterations: " << Iteration << endl
	<< "          PError     : " << PError << endl << endl;
	if( GiveUp )
	{
		cout << "Gave up because adaptivity was being focused on less than 0.0225% of nodes!" << endl
		<< "(" << NumberOfSolverPoints << " nodes)" << endl << endl; 
	} 
	
} 



Matrix GhostFluidMethod(Matrix& X, Matrix& Y, Matrix& Phi, 
   Matrix& Diffusivity, 
   Matrix& SourceFunction, Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance )
{
 Matrix Output = GhostFluidMethod_Generic_MatrixForm(X,Y,Phi,Diffusivity, 
   SourceFunction,SourceFunctionU, 
   LeftBC,LeftBCtype, RightBC,RightBCtype, 
   BottomBC,BottomBCtype, TopBC,TopBCtype, 
   JumpCondition,NormalJumpCondition, 
   InitialGuess,MaxIterations,Tolerance,
   gfmImplicitUpdateContinuousD_MatrixForm );
 return Output;
}   

Matrix GhostFluidMethod(Matrix& X, Matrix& Y, Matrix& Phi, 
   double (*Diffusivity)(double,double), 
   Matrix& SourceFunction, Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance )
{
 Matrix Output = GhostFluidMethod_Generic(X,Y,Phi,Diffusivity, 
   SourceFunction,SourceFunctionU, 
   LeftBC,LeftBCtype, RightBC,RightBCtype, 
   BottomBC,BottomBCtype, TopBC,TopBCtype, 
   JumpCondition,NormalJumpCondition, 
   InitialGuess,MaxIterations,Tolerance,
   gfmImplicitUpdateContinuousD );
 return Output;
}   
  
  /** 

Matrix WithOxygenGhostFluidMethod(Matrix& X, Matrix& Y, Matrix& Phi, 
   Matrix& Diffusivity, 
   Matrix& SourceFunction, Matrix& SourceFunctionU, 
   double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double), 
   Matrix& InitialGuess, int MaxIterations, double Tolerance )
{
 Matrix Output = WithOxygenGhostFluidMethod_Generic_MatrixForm(X,Y,Phi,Diffusivity, 
   SourceFunction,SourceFunctionU, 
   LeftBC,LeftBCtype, RightBC,RightBCtype, 
   BottomBC,BottomBCtype, TopBC,TopBCtype, 
   JumpCondition,NormalJumpCondition, 
   InitialGuess,MaxIterations,Tolerance,
   gfmImplicitUpdateContinuousD_MatrixForm );
   

   WithOxygenGhostFluidMethod_Generic_MatrixForm(Matrix& X, Matrix& Y, Matrix& Phi, 
   Matrix& Diffusivity, 
   Matrix& SourceFunction, Matrix& SourceFunctionU, 
   double (*PLeftBC)(double),   char PLeftBCtype,  
   double (*PRightBC)(double),  char PRightBCtype,     
   double (*PBottomBC)(double), char PBottomBCtype,   
   double (*PTopBC)(double),    char PTopBCtype,  
   double (*JumpCondition)(double,double), 
   double (*NormalJumpCondition)(double,double), double PTolerance,
  /* Matrix& InitialGuess, */
  /** 
   double (*gfmUpdateFunction)(Matrix&,Matrix&,Matrix&,Matrix&,
                               Matrix&,
							   Matrix&,Matrix&,
							   double(*)(double,double),
							   double(*)(double,double),
							   int,int,double,double),double (*LeftBC)(double),   char LeftBCtype,  
   double (*RightBC)(double),  char RightBCtype,     
   double (*BottomBC)(double), char BottomBCtype,   
   double (*TopBC)(double),    char TopBCtype,  
   double (*DiffusionConstant)(double,double,double,int,int), 
   double (*SourceTimesU)(double,double,double,int,int),
   double (*SourceRemainder)(double,double,double,int,int),
   int MaxIterations, double Tolerance )

 return Output;
}  


***/ 
